2 months ago I showed this bug in wart: arc> (iso :x :x)
nil
(http://arclanguage.org/item?id=18287)This is now fixed. In the process I had to overhaul how wart binds params in fn. It should be a lot more robust, but the code has gotten a lot more complected. I'll try to explain why. In broad terms, traditional lisp evaluators handle lambda binding as follows: Eval all args -> bind sequentially.
When I implemented pervasive keyword args for all params back in 2011 I changed this to: Reorder all args -> Eval all args -> bind sequentially.
Basically it works by first 'pinching out' all keyword args into a table, then successively binding args while looking for candidates in the table.However, wart also added quoted parameters at some point. Useful as a primitive to build macros out of. You could quote a parameter to suppress evaluation of corresponding args at call time. But I kept having to add special cases to support this in the second, eval step above. Eventually, in early 2013 I switched to: Reorder all args -> Bind in param sequence, eval'ing as necessary.
A year later I started noticing more issues. The culprit was parameter aliases, which let me give params distinct names for keyword args. In wart, aliases are fully general and support haskell-like as-patterns (http://www.haskell.org/tutorial/patterns.html): def (foo (xs | (head ... tail))
Here foo will receive an arg called xs, whose car is bound to head, and cdr to tail (the ellipses are like dotted lists in regular scheme/arc). Very useful feature for building generic functions and so on; it let me very straightforwardly overlay features of def and mac atop one another (https://github.com/akkartik/wart/blob/96d90427d9/047generic.wart). However, the cost was additional complexity that I thoroughly under-estimated. What happens if you alias some quoted and some unquoted params, in various orders? In many cases I was silently interpreting the cons inside the alias as a destructured param, which required first eval'ing it, causing the above bug. There were other issues, like this: def (foo ... ('params | (x y)))
some body
(foo 1 :x 2)
Should params be (1 :x 2) or (2 1)? Should the answer change based on whether it's quoted or not?[1] This and other issues basically convinced me that reordering args in advance was no longer defensible. Instead, I am now at this monstrosity: In param sequence, bind keyword or position args eval'ing as necessary.
All structure is gone. But I have a lot more tests and things seem to work much better. Hopefully structure will return in time as I gradually work through possible refactorings.Anyway, I'm still unconvinced that these features are all a good idea as I said before. But at least I have a working prototype to judge over time. A summary of code changes: https://github.com/akkartik/wart/compare/8bcd5212c...96d90427d9 [1] The answer to this question is now always (1 :x 2) regardless of whether or not params is quoted. So I can afford to not have to reorder args when binding it. One new constraint is that param aliases can only include conses and as-params at the end. So this is illegal: (a | (b c) | d)
But these are legal and supported: (a | d | (b c))
(a | (b ... (c | (d ... (e | (f g))))))
|