28

谁能简单解释一下区别?我不认为我从我咨询过的教科书/网站中理解了这个概念。

4

2 回答 2

30

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表达式可以引用ac-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 ... )

在 Racket 中,也可以letrec*在 Scheme 中使用,从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 ... ))

在方案中)。

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

于 2013-02-21T15:28:56.837 回答
29

如果使用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

这一切都文档中。

于 2013-02-21T13:33:56.750 回答