为什么“(读取)”值列表在Scheme中以相反的顺序排列?

时间:2018-12-28 19:16:20

标签: list file io scheme

我正在尝试从Scheme中的文件中读取数据,我想知道为什么在使用(read)(read-line)获取值之后为什么需要反转列表。示例:

]=> (list 1 (read) 2 (read) 3)
Hello
world

;Value 39: (1 world 2 hello 3)

为什么结果列表中“世界”在“你好”之前?干杯。

3 个答案:

答案 0 :(得分:2)

参数的计算顺序按标准未定义。这是part from the R6RS report

  

注意:‌与Lisp的其他方言相反,评估顺序   未指定,以及运算符表达式和操作数   表达式始终使用相同的求值规则求值。

     

尽管未指定评估顺序,但效果   运算符和操作数表达式的任何并发求值   被约束为与   评价。每种评估的顺序可以选择不同   过程调用。

这里是一个示例:

(define (debug x)
  (display x)
  x)

(define (add x y)
  (debug (+ (debug x) (debug y))))

(add (add 3 4)
     (add 5 6))
; ==> 18

以下是display调用的可能结果:

347561171118 ; strictly left to right
651143771118 ; strictly right to left
561134771118 ; ltr in add, rtl in call to add (consistent)
437651111718 ; rtl in add, ltr in call to add (consistent)

作为示例,我知道MIT计划严格从右至左执行,而DrRacket严格从左至右执行。伊卡洛斯获得了第三名。

未充分说明这些原因是为了在编写规范时允许未知的优化。顺序并不总是很重要,特别是如果您习惯于写。如果您需要正确的订单,可以这样写:

(let ((r1 (read)))
  (let ((r2 (read)))
    (list 1 r1 2 r2 3)))

由于绑定总是在您安全之前进行评估。它有一个快捷键,因此您可以将其写为let*

(let* ((r1 (read))
       (r2 (read)))
  (list 1 r1 2 r2 3))

答案 1 :(得分:0)

Scheme语言未定义函数自变量的求值顺序。也就是说,在评估(f (g) (h))时,未定义对g的调用是发生在对h的调用之前还是之后(只有这两者都在对f的调用之前发生) )。

对于您的代码,这意味着未定义对read的两次调用中的哪一个首先发生。在某些实现中,您可能会获得期望的订单,而在其他实现中,您将获得您在此处看到的订单。

为了强制按照您想要的顺序进行调用,应在调用{{1之前使用letdefineread的结果存储在变量中}}。

答案 2 :(得分:-2)

我想我明白了。由于Scheme中的每个列表实际上都是(cons ...)的递归,因此上述列表实际上是:

(cons
  1
  (cons
    (read)        ; (2)
    (cons
      2
      (cons
        (read)    ; (1)
        (cons
          3
          '()
        )
      )
    )
  )
)

因此,很清楚为什么标记为(read)的标记为(1)的对象要早于标记为(read)的标记为(2)的地方。