用于检查范围是词汇还是动态的程序

时间:2015-09-02 04:21:58

标签: scope scheme racket

我发现检查范围是词汇还是动态的程序是下面给出的(来源:http://inst.eecs.berkeley.edu/~cs61a/su10/resources/sp11-Jordy/scope/

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

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

但这怎么可行呢?这应该始终打印'词汇(无论范围是词汇还是动态)对吗?因为在第一个'let'的主体的局部范围内,范围总是被定义为'词汇..如果我错了请纠正我

2 个答案:

答案 0 :(得分:6)

Scheme使用词法作用域,因此代码总是返回lexical。但是,在使用动态作用域的Lisp系统中,scopedynamic表达式中确实是(let ((scope 'dynamic)) ...) ....

为了理解这一点,您必须了解动态范围的实现方式。将每个变量视为具有一堆值。因此,在评估lambda表达式时,值lexical已被推送到scope' s值栈(通过let)。退出let块时,将弹出该值。之后,第二个let块会将值dynamic推送到scope的值堆栈,这是您的函数所看到的。

我非常感谢the explanation from the Emacs Lisp manual关于动态绑定如何在堆栈方面工作。它帮助我真正理解了这个概念。

答案 1 :(得分:6)

test的值不是

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

只是

(lambda () scope)

当你调用(test)时,会评估函数体,它只包含

scope

对于词法范围,这将是在评估定义时生效的绑定中的值,即词法封闭let - 绑定。

对于动态范围,在调用函数之前不会查找scope的绑定 那时,对'lexical的绑定早已消失 - 它只存在于test的定义中。

当你

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

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

类似的功能

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

会按照您建议的方式运作 - 始终返回'whatever - 因为'whatever的绑定在评估scope期间即使在动态设置中也有效。