我正在为GIMP编写脚本并使用let*
,因为它是我拍摄的样本。但它似乎只是一个与let
完全相同的lambda糖。他们为什么不同?他们之间有什么区别?
答案 0 :(得分:9)
它们在变量绑定的顺序上有所不同。以此为例:
> (let ((a 1)(b (+ a 2))) b)
此代码将失败,因为b
需要a
,之前尚未定义。它在同一个let
中定义,但Scheme会将您的所有let
定义仅作为一个语句,并且不允许它们相互引用。在Gambit计划中,它提出了:
*** ERROR IN ##raise-unbound-global-exception -- Unbound variable: a
相反,let*
将绑定let
的第一个变量,然后绑定第二个变量......等等:
> (let* ((a 1)(b (+ a 2))) b)
3
按预期工作。
感兴趣的第三种形式是letrec
,它不仅允许let
中的变量引用其他变量,而且还让它们自己引用(例如,用于递归)。这使您可以编写如下代码:
> (letrec ((f (lambda(n) ;; Takes the binary log2 recursively
(cond
((= n 1) 0)
(else (+ 1 (f (/ n 2))))))))
(f 256)) ;; 2^8 = 256
8
如果您尝试使用let
或let*
定义递归函数,它会告诉您变量未绑定。
所有这些都可以通过巧妙的重新排列/嵌套let语句来实现,但let*
和letrec
在某些情况下可以更方便和可读。
答案 1 :(得分:4)
它们绑定变量的方式不同。一个let
中的所有变量使用相同的lambda形式,因此您可以这样做:
(let ((x 10) (y 20))
(let ((x y) (y x))
(display (list x y)))) ; prints (20 10)
使用let
切换内部let*
时,您会发现第二个绑定到第一个绑定中绑定的内容而不是let*
之前的内容
(let ((x 10) (y 20))
(let* ((x y) (y x))
(display (list x y)))) ; prints (20 20)
原因是
(let* ((x y) (y x))
...)
与
相同(let ((x y))
(let ((y x))
...))
答案 2 :(得分:2)
let和let *用于绑定变量,两者都是语法糖(宏),但让*一个接一个地绑定变量(从左到右,或从上到下)。差异也在于不同的范围。让每个变量的范围只是表达式,而不是绑定。在let *中,每个变量的范围是表达式和之前的绑定。 让*你做这样的事情(b a)
...
(let* ((a 1)
(b a))
...)
...
让你不要。
实施let:
(define-syntax let
(syntax-rules ()
((_ (( variable value ) ...) body ...)
(( lambda (variable ...) body ...) value ...))))
let *:
的实现(define-syntax let*
(syntax-rules ()
; pattern for one binding
((_ ((variable value)) body ...)
((lambda (variable) body ...) value))
; pattern for two or more bindings
((_ ((variable value) . other) body ...)
((lambda (variable) (let* other body ...)) value))))