如何用`lambda`重写`let *`?

时间:2013-04-11 01:03:26

标签: scheme lambda

我了解如何将(let ((x v1) (y v2)) e)重写为((lambda (x y) e) v1 v2)。但我不太熟悉let*

我们如何根据lambda和函数应用程序重写(let* ((x v1) (y v2) (z v3)) e)

3 个答案:

答案 0 :(得分:4)

let表达式:

(let ((x v1)
      (y v2))
  e)

等同于以下lambda应用程序,注意到在这里可以按任何顺序评估变量(不强制执行严格的从左到右的顺序),并且一个变量的定义不能引用变量在它之前:

((lambda (x y)
   e)
 v1 v2)

另一方面,这个let*表达式:

(let* ((x v1)
       (y v2)
       (z v3))
  e)

可以转换为一系列嵌套lambda,以确保变量按照用于定义它们的相同顺序进行求值,并且首先定义的变量可以在所有后续引用中引用定义:

((lambda (x)
   ((lambda (y)
      ((lambda (z)
         e)
       v3))
    v2))
 v1)

另一个例子:只有在我们使用第二个转换时,此代码才有效:

(let* ((x 1)
       (y (+ x 1)))
  (+ x y))

正如您所看到的,y引用x的定义只会以这种方式运作:

((lambda (x)
   ((lambda (y)
      (+ x y))
    (+ x 1)))
 1)

最后,这里有两本很棒的在线学习计划书:

答案 1 :(得分:1)

let*只是嵌套的let个实例。例如,

(let* ((x v1)
       (y v2)
       (z v3))
  e)

相同
(let ((x v1))
  (let ((y v2))
    (let ((z v3))
      e)))

这对您理解let*有帮助吗? : - )

更新:OP正在询问(在评论Óscar的帖子中)let*let的区别。这是一个例子:首先,让我们使用let*

(let ((x 42))
  (let* ((x 10)
         (y (+ x 13)))
    y))

返回23(10 + 13)。使用内部x的值,并且外部x的值被遮蔽。

现在,让我们来看看如果我们使用let代替let*会发生什么:

(let ((x 42))
  (let ((x 10)
        (y (+ x 13)))
    y))

返回55(42 + 13)。内部x的值不用于计算y的值;它只在let的主体内生效。

答案 2 :(得分:1)

let*扩展为

的内容

此:

(let* ([a 1] [b (* 2 a)])
  (cons a b))

扩展到:

((lambda (a)
   ((lambda (b)
      (cons a b))
    (* 2 a)))
 1)

这是一种很好的方式来考虑lambda在Scheme中的含义(很好,因为它既简单又准确):它既是程序中的位置的标签,也是的范围绑定变量。在Scheme中,程序中某个位置的标签(就像你可以goto在其他语言中使用或用机器语言分支)总是带有绑定变量的范围。您只能通过提供绑定到其范围内绑定的变量的值来“转到”程序中的某个位置。

Scheme的let是一种说法,“我想创建一个绑定这些变量的范围,但我不想等到以后告诉它们的值。我想指定它们的值是正确的这里。”因此,let只是一个生成lambda的宏,然后在那里提供值。

如果您希望其中一个变量的值是使用另一个变量的表达式,例如ba表示的方式,那么b必须在a的范围内定义。因此let*宏定义了包含前一个变量的范围中的每个连续变量。由于我们有一堆嵌套的作用域,它们是由一堆嵌套的lambdas实现的。

以下是如何告诉Scheme如何将let*重写为一堆嵌套的lambdas和函数应用程序:

(define-syntax let*
  (syntax-rules ()
    [(__ () body ...)
      (begin body ...)]
    [(__ ([v e] [v* e*] ...) body ...)
      ((lambda (v)
         (let* ([v* e*] ...)
           body ...))
       e)]))

(let* ([a 1] [b (* 2 a)])
  (cons a b))
=> (1 . 2)

Chez Scheme中,您可以在REPL中输入(expand '(let* ([a 1] [b (* 2 a)]) (cons a b))并查看结果。这是我尝试时出现的内容:

(let ([#:a 1]) (let ([#:b (#2%* 2 #:a)]) (#2%cons #:a #:b)))