为什么可以重新定义 `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 中,lambda
和 define
是编译器阶段的顶级绑定。 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!
我不明白这两个 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 中,lambda
和 define
是编译器阶段的顶级绑定。 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!