使用trampoline和Y combinator的代码是否应该在具有动态范围的lisp中工作?
我有javascript中的lisp,它类似于scheme。它可以用于词法范围和动态范围。我不确定动态作用域是如何工作的,看起来还可以,但当作用域是动态的时,此代码不工作:使用trampoline和Y combinator的代码是否应该在具有动态范围的lisp中工作?,lisp,lexical-scope,dynamic-scope,Lisp,Lexical Scope,Dynamic Scope,我有javascript中的lisp,它类似于scheme。它可以用于词法范围和动态范围。我不确定动态作用域是如何工作的,看起来还可以,但当作用域是动态的时,此代码不工作: (define Y (lambda (h) ((lambda (x) (x x)) (lambda (g) (h (lambda args (apply (g g) args))))))) (define (trampoline f) (lam
(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))
当作用域为词法时,它工作良好。当作用域是动态的时,此代码是否应该工作?现在它什么也不做,我不知道为什么,但我想确保在我开始调试之前,这段代码能够正常工作,并因此中断我的动态范围
我的lisp with demo就在这里,但是用于词法范围的代码还没有发布,所以它不会工作。它位于devel branch中,我可以使用它或使用堆栈片段创建codepen演示。我不知道trampoline如何处理动态范围
简化评估:
(define Y ...)
现在Y与某个值绑定
(define (trampoline f)
(lambda args
(let ((result (apply f args)))
...)))
现在蹦床绑定到λfλargs,让结果应用到λf args
现在!一定是在蹦床上。。。n1
我们首先评估内部调用,因此需要解决!并将其应用于1000
根据定义!上面我们将n绑定到1000并评估蹦床。。。n1
我们需要叫蹦床。根据上面蹦床的定义,我们把f和。。。并返回lambda args,让结果应用于参数
我们从蹦床上回来,解开f的束缚
我们现在需要计算lambda参数,让结果应用于f参数。。。n 1将蹦床的返回值应用于n和1
n当前绑定为1000,因此此表达式变为lambda args让结果应用于f args。。。1000 1. 为了执行调用,我们将args绑定到1000 1
现在我们需要计算apply f args,将结果绑定到result,作为let的一部分。apply位于标准库中。args刚刚绑定到1000 1以上。但对f没有约束力
在这一点上,我们应该抛出一个错误:到目前为止,我们看到的f的唯一绑定是在调用trampoline期间,其中f是一个参数。但该调用已经返回,绑定已被删除,因此f是未绑定的
使用Perl版本的代码进行实时演示,其中所有绑定都是手动动态的:
它会像预期的那样爆炸:不能使用未定义的值作为行local$result=$f->@args的子例程引用;因为$f是未绑定的
如果您将所有绑定更改为词法替换所有出现的local by my,$fac->5将按预期返回120。我不知道trampoline如何处理动态范围
简化评估:
(define Y ...)
现在Y与某个值绑定
(define (trampoline f)
(lambda args
(let ((result (apply f args)))
...)))
现在蹦床绑定到λfλargs,让结果应用到λf args
现在!一定是在蹦床上。。。n1
我们首先评估内部调用,因此需要解决!并将其应用于1000
根据定义!上面我们将n绑定到1000并评估蹦床。。。n1
我们需要叫蹦床。根据上面蹦床的定义,我们把f和。。。并返回lambda args,让结果应用于参数
我们从蹦床上回来,解开f的束缚
我们现在需要计算lambda参数,让结果应用于f参数。。。n 1将蹦床的返回值应用于n和1
n当前绑定为1000,因此此表达式变为lambda args让结果应用于f args。。。1000 1. 为了执行调用,我们将args绑定到1000 1
现在我们需要计算apply f args,将结果绑定到result,作为let的一部分。apply位于标准库中。args刚刚绑定到1000 1以上。但对f没有约束力
在这一点上,我们应该抛出一个错误:到目前为止,我们看到的f的唯一绑定是在调用trampoline期间,其中f是一个参数。但该调用已经返回,绑定已被删除,因此f是未绑定的
使用Perl版本的代码进行实时演示,其中所有绑定都是手动动态的:
它会像预期的那样爆炸:不能使用未定义的值作为行local$result=$f->@args的子例程引用;因为$f是未绑定的
如果您将所有绑定更改为词法替换所有出现的local by my,$fac->5按预期返回120。否。蹦床和Y组合器使用闭包 动态范围没有闭包,因此引用自由变量的过程/函数表示程序调用堆栈中具有该名称的任何变量 在词法范围中,它是创建lambda时捕获的变量。因此,守则:
(define test 10)
(define (make-adder test)
(lambda (v) (+ test v)))
(define add20 (make-adder 20))
(add20 5)
; ==> 25 in lexical scope
; ==> 15 in dynamic scope
原因很简单。make加法器返回的函数将值20存储为test,而在动态范围中,test是绑定最接近的值,因此它是局部变量10。此外,致电时:
(let ((test 30))
(add20 5))
; ==> 25 in lexical scope
; ==> 35 in dynamic scope
现在,CommonLisp有动态范围和词法范围。动态作用域变量是用defvar、defparameter或声明的special在顶层定义的变量。这很容易出错,因此我们使用*earmuff*对这些变量进行了特殊命名
Sche
me具有可变对象的参数,并且有用于更新和恢复它的语法,以便将其用作动态变量
编辑
我已经测试了你的词法和动态lisp,两者似乎都能正常工作 不。蹦床和Y组合器使用闭包 动态范围没有闭包,因此引用自由变量的过程/函数表示程序调用堆栈中具有该名称的任何变量 在词法范围中,它是创建lambda时捕获的变量。因此,守则:
(define test 10)
(define (make-adder test)
(lambda (v) (+ test v)))
(define add20 (make-adder 20))
(add20 5)
; ==> 25 in lexical scope
; ==> 15 in dynamic scope
原因很简单。make加法器返回的函数将值20存储为test,而在动态范围中,test是绑定最接近的值,因此它是局部变量10。此外,致电时:
(let ((test 30))
(add20 5))
; ==> 25 in lexical scope
; ==> 35 in dynamic scope
现在,CommonLisp有动态范围和词法范围。动态作用域变量是用defvar、defparameter或声明的special在顶层定义的变量。这很容易出错,因此我们使用*earmuff*对这些变量进行了特殊命名
Scheme具有可变对象的参数,并且有用于更新和恢复它的语法,以便将其用作动态变量
编辑
我已经测试了你的词法和动态lisp,两者似乎都能正常工作 哦,看来我的动态范围毕竟是错的,因为它应该抛出错误,f是未定义的,它什么也不做。它是抛出的,但只是在控制台中,因为它是在承诺中。哦,所以看来我的动态范围毕竟是错误的,因为它应该抛出错误,f是未定义的,它什么也不做。它抛出了,但只是在控制台中,因为它是在承诺中。