在此代码段中:
(begin
(define f '())
((lambda ()
(set! f (lambda (x) (g x 5)))))
(define (g x y) (+ x y))
(f 5))
当评估 (set! f (lambda...))
时,变量g不绑定到任何位置 . 正如R5RS的规范(链接here)所说:
评估lambda表达式时生效的环境将作为该过程的一部分被记住 . 当稍后使用一些实际参数调用该过程时,将通过将形式参数列表中的变量绑定到新位置来扩展评估lambda表达式的环境,相应的实际参数值将存储在这些位置中,并且lambda表达式主体中的表达式将在扩展环境中按顺序计算 .
其中“有效环境”定义为:
命名位置的标识符称为变量,并且被称为绑定到该位置 . 在程序中的某个点上有效的所有可见绑定的集合被称为此时有效的环境 .
所以内在的lambda应该只捕获像 {f: (location #1)}
这样的环境;当通过调用 (f 5)
进行评估时,用于评估其正文的环境应为 {f: (location #1), x: (location #2)}
,其中不包含 g
.
但DrRacket(以及petite,这是一个R6RS实现)在评估上述片段时提供了10个 . 所以环境确实包含 g
. 为什么?
=====
似乎该方案要求define语句仅出现在 <body>
的开头 . 但是这段代码片段也会返回10:
(begin
(define (f x) (g x 5))
(define (g x y) (+ x y))
(f 5))
2 回答
我想我找出了原因 .
R5RS说:
其中letrec被描述为:
对于顶级定义:
这样的行为是可以接受的 .
因此,R5RS因此意味着
意思是一样的
或者,更简单
在我的(有限)经验中,首先使用"let"绑定表单( let , let* , letrec )进行编程总是更加清晰,并尽可能避免使用 set! . 当我这样做时,我发现我的程序更容易理解,特别是几个月后我回来看它们!