'(dyn n 4 (inc 10))' should be 4+4i, not 5
Re this comment: http://arclanguage.org/item?id=21359
I discovered a bug in my own implementation just playing around with that example. But if we write inc.10 in the simpler way, as (inc 10):
Your implementation (chime 0.4.0 executable on Windows):
> (dyn n 4 (inc 10))
5
I was pleased to see your implementation nailing this one. (Unpacking it, since inc is implemented as (def inc (n) (+ n 1)), and since dynamic bindings trump lexical bindings (!), (+ n 1) evaluates as (+ 4 1).)
Then I ran it against my implementation:
> (dyn n 4 (inc 10))
4+4i
What's going on here is that another function simplify (in the dynamic call tree of +), also contains a lexical variable that get shadowed by the dynamic n. (There might be others, but this is the one I found.) Your implementation doesn't expose this, because + has been implemented natively.
I wish I was 100% confident that 4+4i is the "right" answer. (If you ask me, the behavior of dynamic variables is weird and deleterious, and I think it would make sense to have a section in the documentation that advises in quite strong words to use dynamic variables (a) sparingly, and (b) with a naming convention that's guaranteed not to collide with bel.bel code or other people's code.)
The general approach for my implementation will be to "fast-path" people who don't define dynamic variables that clash with lexical variables defined in functions, and to "slow-path" people who do. That's handwaving it a bit, but not much.
On the other hand, both our implementations nail the second example from that comment, related to macros (expanded at eval time) and dynamic variables:
> (repeat 5 prn!hello)
hello
hello
hello
hello
hello
nil
> (dyn init 'prn!4 (repeat 5 prn!hello))
4
4
hello
hello
nil
I wasn't sure either implementation would get that one right; nice. Anyway, it's going to be important to "preserve" this behavior even in the face of various optimizations. Dynamic variables de-optimize everything.