有人能简单解释一下这个区别吗?我不认为我理解我所咨询的教科书/网站的概念。
答案 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
表达式可以引用b
和a
。 a-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。