由于let和let *之间的差异而感到困惑

时间:2013-02-21 13:30:02

标签: scheme let

有人能简单解释一下这个区别吗?我不认为我理解我所咨询的教科书/网站的概念。

2 个答案:

答案 0 :(得分:29)

Let 是平行的,(有点;见下文) let* 是顺序的。 Let 翻译为

((lambda(a b c)  ... body ...)
  a-value
  b-value
  c-value)

let*

((lambda(a)
    ((lambda(b)
       ((lambda(c) ... body ...)
        c-value))
     b-value))
  a-value)

因此创建了嵌套范围块,其中b-value表达式可以引用a,而c-value表达式可以引用baa-value属于外部范围。这也等同于

(let ((a a-value))
  (let ((b b-value))
    (let ((c c-value))
      ... body ... )))

还有 letrec ,允许递归绑定,其中所有变量和表达式都属于一个共享范围,并且可以相互引用(有一些与初始化有关的警告)。它等同于

(let ((a *undefined*) (b *undefined*) (c *undefined*))
  (set! a a-value)
  (set! b b-value)
  (set! c c-value)
  ... body ... )

in Racket,也可在Scheme中以 letrec* 的形式提供,自R6RS)或

(let ((a *undefined*) (b *undefined*) (c *undefined*))
  (let ((_x_ a-value) (_y_ b-value) (_z_ c-value))   ; unique identifiers
    (set! a _x_)
    (set! b _y_)
    (set! c _z_)
    ... body ... ))

in Scheme)。

更新:let实际上不会并行评估其值表达式,只是它们都在let表单出现的同一初始环境中进行评估。基于lambda的翻译也清楚地表明了这一点:首先,在同一个外部环境中评估值表达式,并且收集结果值,并且仅 然后 为每个 id 创建新位置,并将值放在其位置。如果其中一个值表达式改变后续访问的存储(即数据,如列表或结构),我们仍然可以看到顺序性。

答案 1 :(得分:25)

如果您使用let,则无法引用出现在同一let表达式中的其他绑定。

例如,这不起作用:

(let ((x 10)
      (y (+ x 6))) ; error! unbound identifier: x
  y)

但是如果您使用let*,则可以引用出现在同一let*表达式中的之前的绑定:

(let* ((x 10)
       (y (+ x 6))) ; works fine
  y)
=> 16

文档中的全部是here