0

在此代码段中:

(begin
  (define f '())
  ((lambda ()
     (set! f (lambda (x) (g x 5)))))
  (define (g x y) (+ x y))
  (f 5))

(set! f (lambda...))被评估时,变量 g 不绑定到任何位置。正如 R5RS 的规范(链接在这里)所说:

计算 lambda 表达式时生效的环境将作为过程的一部分被记住。当稍后使用一些实际参数调用过程时,将通过将形式参数列表中的变量绑定到新位置来扩展评估 lambda 表达式的环境,相应的实际参数值将存储在这些位置,并且lambda 表达式主体中的表达式将在扩展环境中按顺序计算。

其中“有效环境”在某一时刻被定义为:

命名位置的标识符称为变量,并且被称为绑定到该位置。在程序中某个点生效的所有可见绑定的集合称为该点生效的环境。

所以内部 lambda 应该只捕获像这样的环境{f: (location #1)};并且当通过调用(f 5)用于评估其主体的环境来评估它时,它应该是{f: (location #1), x: (location #2)}不包含g.

但是 DrRacket(还有 petite,它是一个 R6RS 实现)在评估上述代码段时给出了 10。所以环境确实包含g. 为什么?

=====

似乎该方案要求定义语句仅出现在<body>. 但此代码段也返回 10:

(begin
  (define (f x) (g x 5))
  (define (g x y) (+ x y))
  (f 5))
4

2 回答 2

1

我想我找到了原因。

R5RS 说:

A <body> containing internal definitions can always be converted into
a completely equivalent letrec expression

其中letrec被描述为:

The <variable>s are bound to fresh locations holding undefined values,
the <init>s are evaluated in the resulting environment (in some
unspecified order), each <variable> is assigned to the result of the
corresponding <init>, the <body> is evaluated in the resulting
environment

对于顶级定义:

Scheme 的一些实现使用初始环境,其中所有可能的变量都绑定到位置,其中大多数包含未定义的值。这种实现中的顶级定义真正等同于分配。

所以这种行为是可以接受的。

于 2014-02-07T20:49:45.467 回答
1

因此,R5RS 因此意味着

(begin
   (define f '())
   ((lambda () (set! f (lambda (x) (g x 5))) ) )
   (define (g x y) (+ x y))
   (f 5) )

意思是一样的

(letrec
    ((f '())
     (g +)
     (x x)
     (y y) )
 (f 5) )

或者,更简单地说

(let*
    ((g +)
     (f (lambda (x) (g x 5)) ) )
  (f 5) )

在我(有限的)经验中,首先使用“let”绑定形式( letlet*letrec )进行编程总是更清晰,并且避免设置!越多越好。当我这样做时,我发现我的程序更容易理解,尤其是当我几个月后回来查看它们时!

于 2014-02-08T20:46:52.720 回答