首页 > 解决方案 > 如何测试动态范围是否已在 lisp 中正确实现?

问题描述

我有基于 JavaScript 中方案的简单 lisp 实现。默认情况下它具有词法范围,但我刚刚添加了动态范围作为选项。我如何测试我是否正确实现了这一点:

此代码打印 20 和 30:

(define (foo x) (* x y))

(define y 1)

(let ((y 2))
   (print (foo 10))
   (let ((y 3))
       (print (foo 10))))

所以值 y 是动态的,因为它为函数 foo 改变了我需要做些什么来使 lisp 动态化,或者是这样吗?

let 和函数调用是唯一可以观察动态范围的地方吗?

标签: lispdynamic-scope

解决方案


我还需要做些什么来使 lisp 动态化,或者就是这样?

foo看到绑定设置的事实y是一个重要的测试用例,它让我们相信一些动态范围的复制正在发生。

另一个重要的测试是表明动态绑定没有被词法闭包捕获

假设我们 bind y,然后调用一个类似的函数,foo而不是仅仅打印一个基于y捕获其主体的词法闭包的计算。然后在我们绑定的范围之外y,我们称之为返回的闭包。该闭包必须不再看到y我们绑定的值。引用的闭包主体必须始终在当前动态环境中y看到 的值。y

您可能认为这是理所当然的,但您会惊讶于动态范围的某些实现很容易出错。如果您有某种用于实现动态范围的动态环境指针,并且该指针不知何故卷入了词法闭包中,哎呀,您现在有了捕获动态环境的闭包。(当然,这可以是一个特性:“动态闭包”)。动态变量的“调用函数查看父绑定”方面在动态闭包下工作得很好;这是一个独立的问题。

作为旁注,如果您(define y 1)正在创建一个动态变量,那么词法变量是如何定义的?如果你想在同一个方言中同时支持动态和词法范围,你必须有一种方法来指定哪些符号将服从动态绑定,哪些将保持词法。

即,由于您“作为选项”支持动态范围,因此您需要有一种方法使其与词法范围的默认选项共存,并对此进行测试(您没有破坏词法范围)。

Common Lisp 通过将实际符号标记为特殊来做到这一点,这是由defvar和完成的defparameter

在 Scheme 中,(define ...)表单不做任何这样的事情,如果你让它这样做,你就破坏了语言;如果你想在保持与 Scheme 兼容的同时拥有类似 CL 的动态变量,你需要一些其他的形式来(define-dynamic y ...)标记y动态绑定的符号。


推荐阅读