检查作用域是词法作用域还是动态作用域的程序

6

我发现检查作用域是否为词法或动态的程序如下(来源:http://inst.eecs.berkeley.edu/~cs61a/su10/resources/sp11-Jordy/scope/

(define test 
  (let ((scope 'lexical)) 
    (lambda () scope)))

(let ((scope 'dynamic)) 
  (test))

但是这怎么可能呢?这应该总是打印“lexical”(无论作用域是词法的还是动态的),因为在第一个“let”的主体的本地作用域中,作用域始终被定义为“lexical”。如果我错了,请纠正我。
2个回答

7

The value of test is not

(let ((scope 'lexical)) 
    (lambda () scope))

it is just

(lambda () scope)

当你调用它时,(test),函数体将被评估,且仅由以下内容组成:
scope

在词法作用域中,变量的值是在定义时生效的绑定值,即与之有词法关联的let绑定。

而在动态作用域中,只有在函数被调用时才能查找到scope的绑定。
这时,与'lexical有关的绑定已经不存在了——它只存在于test的定义过程中。

当你

(let ((scope 'dynamic)) 
  (test))

在环境中引入了一个新的绑定,这个绑定是在查找scope时找到的。

类似的函数

(define test  
    (lambda () 
        (let ((scope 'whatever))
            scope)))

您提供的建议似乎可行 - 即始终返回'whatever',因为在动态设置中,在评估作用域时绑定到'whatever'的代码仍然有效。

6
Scheme使用词法作用域,因此该代码始终返回“lexical”。然而,在使用动态作用域的Lisp系统中,scope确实会在“(let ((scope 'dynamic)) …)”表达式内部变为“dynamic”……。
为了理解这一点,您必须了解如何实现动态作用域。将每个变量视为具有值堆栈。因此,在评估lambda表达式时,“lexical”值已被推送到“scope”的值堆栈(通过“let”)。当退出“let”块时,该值被弹出。稍后,第二个“let”块将“dynamic”值推送到“scope”的值堆栈中,这就是您的函数看到的内容。 我非常感谢Emacs Lisp手册对动态绑定如何以堆栈形式工作的解释。它帮助我真正理解了这个概念。

我理解了链接中的程序和这里解释的堆栈概念。感谢提供信息。但是,当从第二个“let”调用测试函数时,定义块内的代码将被执行,并且测试函数内的let块应该在执行lambda块之前再次将值“lexical”推入堆栈,对吗?...或者我的执行理解有什么问题? - Subin Pulari
2
@SubinP 当你调用函数时,define 不会被执行,函数已经被定义为 (lambda () scope) - molbdnilo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接