Scheme / Racket:做循环评估顺序

时间:2010-09-14 22:06:57

标签: racket operator-precedence do-loops

以下程序在方案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))。如果不能保证,那么我的程序不是很稳定。

我没有在任何一种语言的标准中看到任何指定这一点,但我在这里问,因为我测试的时候按顺序进行了评估。

1 个答案:

答案 0 :(得分:7)

一般不保证按顺序对它们进行评估,但结果仍然相同。这是因为这里没有副作用 - 循环不会改变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评估 保证是从左到右。当有副作用时这很重要--Backet喜欢可预测的行为,而其他人反对它,声称这会导致人们对隐含依赖于此的代码。一个显示差异的常见小例子是:

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