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
的变量与之相矛盾,而且确实是错误的。