为什么可以重新定义 `lambda`?

Why can you redefine `lambda`?

我不明白这两个 Scheme 程序之间的以下行为:

程序 1:

(define a
  (begin
    (display "hmmm")
    (newline)
    lambda))

这个程序 运行 使用 scheme test.ss,在 lambda 行给我一个语法错误,但没有打印出字符串 "hmm".

程序 2:

(define lambda 5)
(define a (+ 1 2 lambda))

这里的最终结果是a等于8


第一个程序中的行为是我期望两个程序中的行为。让我感到困惑的是为什么第二个程序不会因语法错误而失败。很明显,我正在重新定义 lambda,但我认为在该代码实际上是 运行 之前,这会因语法错误而失败。在我看来,要知道这是 不是 语法错误,您实际上需要 运行 程序,但如果这是行为,那么我会期待第一个程序在出错之前显示字符串。

简而言之,为什么第一个程序会导致语法错误,而第二个程序不会?

正如 Alexis 提到的,重新定义 lambda 是完全没问题的。

在您的第一个示例中,您在参数 a(display "hmmm")(newline)lambda 上调用过程 define。由于 Scheme 是一种急切的语言,它会尝试在执行之前 评估 每个参数,这很可能是它在评估 lambda 时失败的原因(因为在这种情况下,lambda 是一个需要一些参数的过程-编号:https://docs.racket-lang.org/guide/lambda.html).

第二个例子成功了,因为当对参数 a 和求和 (+ 1 2 lambda) 调用 define 时,求和解析为有形类型(因为 lambda 已被重新定义为整数).

希望对您有所帮助。

在 Scheme 中,lambdadefine 是编译器阶段的顶级绑定。 define 恰好需要两个操作数,因为您提供了 4 个,所以它应该首先对此做出反应。所以让我们先修复一下:

(define a 
  (begin 
    (display "hmmm")
    (newline)
    lambda)))

现在您收到关于 lambda 的错误。这是创建过程的原始形式,因此编译器认为您使用错误:

(lambda (x) (+ x x)) ; implementation of double

如果您已将 lambda 定义为变量,则不会发生该错误,因为即使这是创建过程的方式,您也可以创建具有相同名称的变量。

(define lambda 10)
(define a 
  (begin (display "hmmm")
  (newline)
  lambda))
; ==> 10 (and it printed "hmmm")

编译器知道代码的词法性质。它确切地知道定义了哪些绑定,哪些绑定在哪个阶段。顶级 lambda 不再可用。

现在在你的第二个程序中定义 lambda 然后使用它,就像我上一个同样有效的例子一样。

请注意,在 R5RS 中,编译器假定重新定义 og 库和原始过程是兼容的,并且可能会常量折叠:

(define (+ a b)
  (string-append a b))
(display (+ 4 5)) ; displays 9

为了辩护,我让我的 + 不兼容,从而违反了 R5RS 报告。如果它不是顶级的,那就没问题了:

(let ((+ (lambda (a b) (string-append a b))))
  (+ 4 5)) ; no loinger top level, will signal n error!