I don't know what it is, but pattern matching like this just doesn't feel very "arcy" to me (and I'm not claiming my ideas are superior or anything...)
I think it has to do with the fact that Haskell uses pattern matching as a comprehensive way for defining all functions. Using a pattern matching library in arc means that for every function I write I would have to decide whether to use the pattern matching definition, or a regular definition, which feels inelegant...
I think an argument could be made to make pattern matching (very much like this) the default behavior for all arc functions... but short of that, I, personally, would probably not use a library like this very often...
However, it looks like an elegant implementation of the concept, so if I had to ever write some code with extremely hairy destructuring I definitely might change my mind an use it in a limited section of code...
> if I had to ever write some code with extremely hairy destructuring I definitely might change my mind an use it in a limited section of code...
Which is the point of every library for every language, anyway. I'd be hard pressed trying to use a matrix library in an IRC bot.
Personally, I find pattern matching to be a powerful way of not having to fiddle with 'caris and what not. I just say "if the user puts this and that and this, then do it this way". I'd argue it removes some amount of bugs, too - I caught a bug in pg's 'varline function because I was trying to convert it to pattern-matching form. Mucking about with car/cdr and friends feels rather low-level to me; and if Arc is attempting to be the highest of high level languages, it certainly shouldn't force the user to think in terms of list nodes.
...the reason it returns nil is I think because (car nil) in arc is nil. I think this is the Right Thing overall, even though an empty list doesn't really have a car.
However, in the case of parameter destructuring we could do better, because during destructuring we could (if it worked this way) supply default optional values to have more intelligent handling if a part of a destructuring encounters an empty list and "runs out" of values to destructure. It would look like this:
arc> (def foo (((o a 'falafel) . b))
a)
#<procedure: foo>
arc> (foo '(bar baz))
bar
arc>(foo nil)
falafel
The value of this would be:
1. List processing functions, among others, could tell when they run out of values for destructuring by checking for the magic optional value
2. It might be possible to get this behavior "for free" without growing the source of arc, since it seems like it might just be a generalization of current destructuring/optional support.
Hmm. A quick check in the arc interpreter reveals that (car nil) and (cdr nil) are both nil, so you're right about that.
However, there could be another reason this is working. In your particular example, the full expanded version of the function call is
(foo . (nil . nil)),
or in other words,
(cons foo
(cons nil
nil)).
So it really should be destructuring that way anyway.
Now, having said that, can anyone give a good reason that (car nil) and (cdr nil) are nil? It seems a little strange to me, although I can see that it helps destructuring.
Yes, you could of course use map for the simple example in the post. I didn't want to make it more complicated than necessary for a post- If you want a more complicated example that can't be done with map, here's a function that removes pairs of identical items from a list:
(def rem-pairs ((a . (b . c)))
(when a
(if (is a b) (rem-pairs c)
(cons a (rem-pairs:cons b c)))))
arc> (rem-pairs '(d r b s d d e w))
(d r b s e w)
This function, also, will work in every case but break when there are nils in the list)
For everything else, there's pattern matching (on nex-3's arc-wiki).
(pat-match:def rem-pairs
( (a b . c) )
(if (is a b)
(rem-pairs c)
`(,a ,@(rem-pairs `(,b ,@c))))
( (a) )
`(,a)
( () ) ())
Possibly I can make it such that you can even say something like (a ,(b (is a b)) . c) in the pattern guard, but it seems a semi-hard problem.
;does not work in current version yet!!
(pat-match:def rem-pairs
( (a ,(b (is a b)) . c) )
(rem-pairs c)
( (a . as) )
`(,a ,@(rem-pairs as))
( () )
() )
I'm still not seeing the win of pattern matching here, I'm afraid. This is actually longer than the standard definition using car/cdr. Maybe it's better for more complicated things, I suppose, but that'll defeat the purpose because it wouldn't be legible at that point (as if it is now).
The big win is that it's assuredly correct, and you don't have to mess around dealing with car and cdr. Crossref def varline in app.arc : arc1 had a bug there because it's ridiculously easy to make a mistake dealing with car and cdr. If you can't find the bug, try rewriting the code into pattern-matching form.
Well, I'd be happy with that, except it doesn't work- There's no way to know with or.a.b if you're at the end of the list or if there's just a nil as a last item in the list. Notice the missing item here:
Ah, I see. When destructuring the arguments, if the last argument is nil it is equivalent to not being an item. ie:
arc> (= a '(1 2 nil))
(1 2 nil)
has a last destructuring bind of (nil . nil) so 'a would be nil and 'b would be nil, making my code not work and making it impossible to differentiate between the end of the list and the list with a last item of nil.
This code shares almost the same amount of brevity, though I believe it defeats the purpose of what you were trying to do with the destructuring bind (make the calls to car/cdr disappear).
I don't believe your solution is the right thing to do because it wouldn't make sense for the car to be optional and then not force the cdr to be optional. I do not believe an optimal destructuring solution exists that could improve on the brevity of the original car/cdr solution.
I noticed this contradiction, too... :)
If we're not going to use c[ad]r composability, why not just use unique, easily distinguishable names for all of these that don't compose:
car --> hd
cdr --> tl
caar --> inner
cddr --> skip2
cadr --> second
...or something like that. Unique names would reduce errors.