我正在为 GIMP 编写脚本,并let*
在我采集的样本中使用它。但它似乎只是一个与let
. 为什么它们不同?它们之间有什么区别?
3 回答
它们在变量绑定的顺序上是不同的。考虑一下这个例子:
> (let ((a 1)(b (+ a 2))) b)
此代码将失败,因为b
requires a
,它之前没有定义。它是在同一个 中定义的let
,但 Scheme 会将您的所有let
定义视为一个语句,并且不允许它们相互引用。在 Gambit Scheme 中,它提出:
*** 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
or定义递归函数let*
,它会告诉您变量未绑定。
所有这些都可以通过巧妙地重新排列/嵌套 let 语句来实现,但在某些情况let*
下letrec
可以更方便和可读。
它们在绑定变量的方式上有所不同。一个变量中的所有变量都let
使用相同的 lambda 形式,因此您可以这样做:
(let ((x 10) (y 20))
(let ((x y) (y x))
(display (list x y)))) ; prints (20 10)
let
虽然用 a切换内部,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))
...))
let 和 let* 用于绑定变量,两者都是语法糖(宏),但 let* 会一个接一个地绑定变量(从左到右,或从上到下)。不同之处也是范围不同。在 let 中,每个变量的作用域只是表达式,而不是绑定。在 let* 中,每个变量的范围是表达式和之前的绑定。用 let* 你做这样的事 (ba)
...
(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))))