I have lisp in javascript which is similar to scheme. It can be used with lexical and dynamic scopes. I was not sure how dynamic scope works and it's seems ok but this code don't work when scope is dynamic:
(define Y
(lambda (h)
((lambda (x) (x x))
(lambda (g)
(h (lambda args (apply (g g) args)))))))
(define (trampoline f)
(lambda args
(let ((result (apply f args)))
(while (eq? (type result) "function")
(set result (result)))
result)))
(define (! n)
((trampoline (Y (lambda (f)
(lambda (n acc)
(if (== n 0)
acc
(lambda ()
(f (- n 1) (* n acc)))))))) n 1))
(print (! 1000))
it works fine when scope is lexical. Should this code work when scope is dynamic? Right now it just do nothing and I don't know why but wanted to be sure that this code should work before I start debugging and make my dynamic scope break because of this.
My lisp with demo is here https://jcubic.github.io/lips/ but the code that make this work for lexical scope is not yet published so it will not work. (it's in devel branch and I can create codepen demo with it or using Stack Snippet).
I don't see how
trampolinecan work with dynamic scoping.Simplified evaluation:
Now
Yis bound (to some value).Now
trampolineis bound to(lambda (f) (lambda args (let ((result (apply f args))) ...))).Now
!is bound to(lambda (n) ((trampoline ...) n 1)).We evaluate the inner call first, so we need to resolve
!and apply it to1000.By the definition of
!above we bindnto1000and evaluate((trampoline ...) n 1).We need to call
trampoline. By the definition oftrampolineabove, we bindfto...and return(lambda args (let ((result (apply f args))) ...)).We return from
trampolineand undo the binding off.We now need to evaluate
((lambda args (let ((result (apply f args))) ...)) n 1)(applying the return value oftrampolinetonand1).nis currently bound to1000, so this expression becomes((lambda args (let ((result (apply f args))) ...)) 1000 1). To perform the call call we bindargsto(1000 1).Now we need to evaluate
(apply f args)(to bind the result toresultas part oflet).applyis in the standard library.argswas just bound to(1000 1)above. But there is no binding forf.At this point we should throw an error: The only binding of
fwe've seen so far was during the call totrampoline(wherefwas a parameter). But that call has already returned and the binding was removed, sofis unbound.Live demo (using a Perl version of your code where all bindings are made dynamic manually): https://ideone.com/DWjwBj
It blows up as predicted:
Can't use an undefined value as a subroutine referencefor the linelocal $result = $f->(@args);because$fis unbound.If you change all bindings to lexical (replace all occurrences of
localbymy),$fac->(5)returns120as expected.