6

我正在为 GIMP 编写脚本,并let*在我采集的样本中使用它。但它似乎只是一个与let. 为什么它们不同?它们之间有什么区别?

4

3 回答 3

10

它们在变量绑定的顺序上是不同的。考虑一下这个例子:

> (let ((a 1)(b (+ a 2))) b)

此代码将失败,因为brequires 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

如果您尝试使用letor定义递归函数let*,它会告诉您变量未绑定。

所有这些都可以通过巧妙地重新排列/嵌套 let 语句来实现,但在某些情况let*letrec可以更方便和可读。

于 2013-09-18T07:46:39.160 回答
4

它们在绑定变量的方式上有所不同。一个变量中的所有变量都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))
    ...))
于 2013-09-18T11:55:16.097 回答
2

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))))
于 2013-09-18T07:52:50.243 回答