【问题标题】:Scheme/Racket: do loop order of evaluation方案/球拍:做评估的循环顺序
【发布时间】:2011-04-12 09:55:31
【问题描述】:

以下过程在方案 r6rs 和 Racket 中都有效:

;; create a list of all the numbers from 1 to n
(define (make-nums n)
  (do [(x n (- x 1)) (lst (list) (cons x lst))]
    ((= x 0)
     lst)))

我已经对 r6rs 和 Racket 进行了测试,它确实可以正常工作,但我只知道 DrRacket 是肯定的。

我的问题是是否保证步骤表达式(在这种情况下为(- x 1)(cons x lst))将按顺序进行评估。如果不能保证,那么我的程序就不是很稳定。

我在这两种语言的标准中都没有看到任何规定,但我在这里问是因为当我测试时,它是按顺序评估的。

【问题讨论】:

    标签: racket operator-precedence do-loops


    【解决方案1】:

    通常不保证按顺序评估它们,但结果仍然相同。这是因为这里没有副作用 - 循环不会更改 xlst,它只是将它们重新绑定到新值,因此评估两步表达式的顺序无关紧要。

    要查看此内容,请从外观更简洁的代码开始:

    (define (make-nums n)
      (do ([x n (- x 1)] [lst null (cons x lst)])
          [(zero? x) lst]))
    

    翻译成一个有名的-let

    (define (make-nums n)
      (let loop ([x n] [lst null])
        (if (zero? x)
          lst
          (loop (- x 1) (cons x lst)))))
    

    并进一步将其转换为辅助函数(这就是名为-let 的真正含义):

    (define (make-nums n)
      (define (loop x lst)
        (if (zero? x)
          lst
          (loop (- x 1) (cons x lst))))
      (loop n null))
    

    现在应该清楚了,在递归 loop 调用中计算两个表达式的顺序并没有让它做任何不同的事情。

    最后,请注意在球拍评估中保证是从左到右的。当有副作用时,这很重要——Racket 更喜欢可预测的行为,而其他人反对它,声称这会导致人们编写隐含依赖于此的代码。一个显示差异的常见小例子是:

    (list (read-line) (read-line))
    

    在 Racket 中保证返回读取的第一行的列表,然后是第二行。其他实现可能会以不同的顺序返回这两行。

    【讨论】:

    • 编辑:谢谢!这很有趣,我没有意识到do 是这样工作的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-08-07
    • 1970-01-01
    相关资源
    最近更新 更多