简单的让宏

方案中的 let 表达式实际上是宏。他们可以用 lambdas 表达。一个简单的 let 可能看起来像这样:

(let ((x 1) (y 2))
  (+ x y))

当返回 let 体的最后一个表达式的值时,它将返回 3。如你所见,let-expression 实际上正在执行某些操作。如果我们用 lambdas 翻译这部分代码,我们会得到这样的结果:

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

在这里我们可以看到我们直接用 1 和 2 调用匿名 lambda。所以在这种情况下的结果也是 3。

考虑到这一点,我们理解 let 表达式由两部分组成。它有参数和像 lambda 一样的体,但区别在于,在评估后立即调用表达式。

为了解释 let 表达式如何从抽象到具体的视图,它看起来像这样。

(let params body ...)
(let (param1 param2 ...) body ...)
(let ((p1 val1) (p2 val2) ...) body ...)

参数是在 let 的主体中使用的一对 (name value) 的列表。

为何使用 let 表达式?

让表达式在方法中存储变量特别有用,就像在类似语言中初始化变量一样。使用 define 是有利的,因为在 let 表达式之外,变量已经消失了……使用 define 实际上是在当前执行环境中添加一个变量。无法删除添加到全局环境的变量。让表达在任何地方都可以安全使用。它也可以用于重影变量而不触及父范围。

例如:

(let ((x 1))
  (let ((x 2) (y x))
    (display x)
    (display y))
  (display x))

它将打印:

2
1
1

在这种情况下,x 定义为 1,然后由第二个 let 中的 x 重影,值为 2。变量 y 以父范围的值 x 启动。执行内部 let 表达式后,它会显示 x 的初始值为 1.内部 let 表达式不会更改父范围的值。

每当你需要初始化变量时,你应该使用这样的 let 表达式:

(let (
  (user (get-current-user session))
  (db (get-current-db session))
  (ids (get-active-ids session))
  )
  (mark-task-completed db user ids)
  (change-last-logged db user)
  (db-commit db))

在这个例子中,变量被初始化并在代码块中多次使用。当 let 表达式完成时,变量会自动释放,因为它们不再是必需的。