2

我不理解这两个方案程序之间的以下行为:

程序 1

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

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

方案二

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

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


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

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

4

2 回答 2

1

正如 Alexis 所提到的,重新定义 lambda 是完全可以的。

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

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

希望有帮助。

于 2017-08-06T16:10:37.563 回答
1

在 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!
于 2017-08-06T17:48:37.067 回答