Scheme 动态范围返回未定义的变量
在动态范围假设下,下面的代码将返回错误Scheme 动态范围返回未定义的变量,scheme,programming-languages,dynamic-scope,Scheme,Programming Languages,Dynamic Scope,在动态范围假设下,下面的代码将返回错误 (let ((f (lambda (g) (lambda (n) (if (zero? n) 1 (* n ((g g) (- n 1)))))))) ((f f) 5)) 我的答案是0,因为: n*(n-1)*(n-2)*(n-3)*(n-3)*(n-4)*1;; since the call with n=0, n bound to 0 0*0*0*0*1 这里缺少什么?使用动态范围,g将未定义,因为第6行没有
(let ((f (lambda (g)
(lambda (n)
(if (zero? n)
1
(* n ((g g) (- n 1))))))))
((f f) 5))
我的答案是0,因为:
n*(n-1)*(n-2)*(n-3)*(n-3)*(n-4)*1;; since the call with n=0, n bound to 0
0*0*0*0*1
这里缺少什么?使用动态范围,
g
将未定义,因为第6行没有名为g
的变量。(定义测试
(让((x 10))
(lambda()x)))
这里我们从x
是局部变量的范围返回lambda函数。在词法作用域下,将环境附加到创建的lambda函数。这个环境由绑定变量组成,这些变量位于创建lambda函数时可用的自由变量之上——这里,x
,绑定到10。因此,当调用此返回的lambda函数时,其x
只能是10
在动态范围内,let
是死代码。创建的lambda函数不存储其词法环境,因此在调用时,x
将在调用的实际时间进行新的查找。此时,名为x
且值为10
的变量将不再存在。lambda查找到的x
将是您在调用时绑定到的x
:
(let((x20))
(测试)
; ==> 20
当然:
(测试);==错误:未绑定变量x
所以对于你的代码来说,这是同样的问题。当计算(lambda(n)…
时,无论g
是什么,创建lambda函数,在返回lambda函数时超出范围,因此当调用返回的lambda函数时,g
将被重新查找,并且将是调用时绑定到的任何g
,与以前一样。为了使其在动态范围内工作,您可以执行以下操作:
(let((f)λ(gn)
(如果(零?n)
1.
(*n(gg(-n1(())())))
(f)(5)
这里的区别在于g
从不超出范围。这在动态和词汇范围内都有效。您可以将其简化为动态范围,如下所示:
(let((f(lambda(n);(lambda(f)(f5))
(如果(零?n);(λ(n)
1;(如果(零?n)
(*n(f(-n1()()())));1
(f 5);(n(f(-n 1())))
在词法范围中,f
inside(lambda(n))
是未绑定的变量,但在动态范围中,首先建立f
,在调用(f5)
之后,它仍然可用于所有嵌套调用,(f4)
,(f3)
等,直到(f5)
inside的求值(lambda(f)(f5))
完成;只有在f
被解除建立和销毁时,该lambda
退出并返回(f5)
的结果
在中,他提到论文中有一个bug。第一个高阶函数,
maplist
,将x
作为list参数的名称。在演示中,他将一个函数传递给maplist
,该函数将x
作为参数。这两个函数在第一对参数后发生碰撞,因此它不会发生错误由于动态范围,ot工作。动态范围极易出错,在通用Lisp中,所有全局变量都是动态的,*earmuff*
命名约定是必要的,以避免无数个小时找到全局变量,从而改变函数,使其执行与预期完全不同的操作。谢谢,为什么?有什么不同?为什么g未绑定到f?@David,因为它是动态作用域。在计算(f f)
时,g
确实绑定到f
。但是当计算(返回的lambda 5)
时,g
不再绑定,因为它使用调用作用域,而不是封闭作用域。因此表达式(g)
产生了一个错误。你的答案肯定是错的。你在评论中也说了那么多。@WillNess怎么会这样?“在计算(f)
时,g
确实与f
“是正确的。”当你执行((f)5)
时,没有名为g
的变量与之相矛盾,而且确实是错误的。