8

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

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

4

3 回答 3

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的 s,以确保变量的评估顺序与用于定义它们的顺序相同,并且首先定义的变量可以在所有后续定义中引用:

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

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

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

可以看到,yreferences的定义x,只有这样才能起作用:

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

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

于 2013-04-11T01:14:57.733 回答
1

let*扩展到什么

这个:

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

扩展为:

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

这是一个很好的方式来思考lambdaScheme 中的含义(很好,因为它既简单又准确):它既是程序中位置的标签,是绑定变量的范围。在 Scheme 中,程序中某个位置的标签(例如您可以goto在其他语言中执行的操作或在机器语言中的分支)始终与绑定变量的范围一起使用。您只能通过提供绑定到其范围内的变量的值来“转到”程序中的某个位置。

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

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

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

(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)))
于 2013-04-11T02:07:51.330 回答
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.

于 2013-04-11T01:13:07.040 回答