No need to go to SICP. When
(foo 3) gets evaluated in newLISP, the value of
x is gone from the stack (it gets popped off), and without the environment carried by a closure to remember it, it gets forgotten. So then
the value of (foo 3) (with the lost value of
x) gets applied to the argument 4 and the evaluator complains that there is no
x. We might not like this, but it does work as advertized.
For that example to work as the fellow intended, it needs to have the binding of
x hang around in an environment (part of the closure) -- if only for a moment. However, in newLISP, what you want to do is just have any reference to
x expanded on the fly. If this can be done, then in this case, there is no need to have environments hang around.
Code: Select all
> (define (foo* x) (letex (x x) (lambda (y) (+ x y))))
> ((foo* 3) 4)
7
;; Here's what's really happening with (foo* 3):
> (foo* 3)
(lambda (y) (+ 3 y))
;; Here is what happens with (foo 3):
> (foo 3)
(lambda (y) (+ x y))
;; The following works, because the value of x is still on the stack:
> ((lambda (x) ((lambda (y) (+ x y)) 4)) 3)
7
Of course, closures are neat for other reasons, but in this case, it is no great loss (or any loss), since all you really need to do is just "fill in" the value of
x on the fly -- a way for doing that in newLISP is to expand the reference to
x in that lambda expression on the fly.
P. S. -- And BTW, having closures will still not make me look sexy in my jeans. (Little board spam reference there. :)
(λx. x x) (λx. x x)