【问题标题】:Race condition between nested applications of (define ...)?(define ...) 的嵌套应用程序之间的竞争条件?
【发布时间】:2013-09-03 19:06:13
【问题描述】:

在 linux 和 Mac OS 上使用 DrRacket,下面的代码给出了这个错误

*: expects type <number> as 1st argument, given #<undefined>

但如果我在过程定义的开头取消注释(换行符),它可以正常工作,产生预期值 9。

#lang r5rs

(define (quadr x y)
        ;(newline)
        (define xx (* x x))
        (define yy (* y y))
        (define xxyy (* xx yy))
        (+ xx yy xxyy))

(display (quadr 1 2))
(newline)

这是 Racket 的方案解释器中的一个错误,还是指定的语言使得 (define ...) 的嵌套调用可能发生乱序?如果是后者,我在哪里可以找到语言规范的相关部分?

顺便说一句,我非常了解“let”结构,并且知道这不是定义此类过程的推荐方式。不过,我没想到会出现这个错误。

【问题讨论】:

  • 不一定推荐在内部定义上使用let。 Racket 程序员特别倾向于内部定义,因为#lang racket 支持更多语法形式的内部定义。

标签: lisp scheme racket race-condition


【解决方案1】:

这里是 R5RS 规范的相关link,解释了内部定义的行为。请注意,在第 5.2.2 节中声明:

...必须可以评估&lt;body&gt; 中每个内部定义的每个&lt;expression&gt;,而无需分配或引用任何正在定义的&lt;variable&gt; 的值。

换句话说,如果您的 define 值依赖于同一内部定义中先前的 defined 值,则您不能指望正确的行为。为此使用let*:

(define (quadr x y)
  (let* ((xx   (* x x))
         (yy   (* y y))
         (xxyy (* xx yy)))
    (+ xx yy xxyy)))

或者更详细一点,使用几个嵌套的lets:

(define (quadr x y)
  (let ((xx (* x x))
        (yy (* y y)))
    (let ((xxyy (* xx yy)))
      (+ xx yy xxyy))))

插入(newline) 会导致变量定义在此示例中起作用,这是非常奇特的,但是当您处理未定义的行为时,任何事情都可能发生。附带说明一下,如果我使用#lang racket 而不是#lang r5rs,则原始代码对我有效,而无需额外的(newline)。

【讨论】:

  • 回复您的最后一条评论:R5RS 具有 letrec 内部定义语义,R6RS 和 R7RS 具有 letrec* 语义。这就是为什么您会看到不同的行为,具体取决于您是否使用#lang r5rs。
  • @ChrisJester-Young 在走自己的路之前,球拍真的改变了他们的语言以符合R6RS吗?
  • @Sylwester 许多球拍开发者都深入参与了 R6RS 的开发,因此 R6RS 和 Racket 在许多方面达成一致也就不足为奇了。
猜你喜欢
  • 2016-11-16
  • 1970-01-01
  • 2018-07-24
  • 1970-01-01
  • 2016-02-02
  • 2013-11-14
  • 2015-05-02
  • 1970-01-01
  • 2022-11-04
相关资源
最近更新 更多