# 10.5 延迟求值（DONE）

在某些情况下，延迟表达式的求值会很有帮助。比如，你可以将耗时的操作推迟到不得不做时，这在很多情况下可以极大的提升效率。thunk 库提供了一系列函数和宏用来支持这种延迟求值：

Macro: thunk-delay forms...

返回一个表达式对应的 thunk。thunk 是一种闭包（closure）（查阅 闭包），此闭包继承了函数 thunk-delay 的词法环境。这个过程中使用了 lexical-binding。（词法绑定）

Function: thunk-force thunk

强制 thunk 求值。这个函数返回求值的最后结果。thunk 会记住以往的求值结果。

Macro: thunk-let (bindiings...) forms...

这个宏和 let 和相似，但是创建一个懒加载变量绑定。任何绑定都应该是 (symbol value-form) 的形式。和 let 不同的是，其中的变量绑定会延迟到该符号第一次使用。使用这个宏需要 lexical-binding。

例：

```
(defun f (number)
  (thunk-let ((derived-number
              (progn (message "Calculating 1 plus 2 times %d" number)
                     (1+ (* 2 number)))))
    (if (> number 10)
        derived-number
      number)))

(f 5)
⇒ 5

(f 12)
-| Calculating 1 plus 2 times 12
⇒ 25
```

由于延迟绑定变量的特殊性，设置它们（例如使用`setq`）会抛出错误。

Macro: thunk-let\* (bindings...) forms...

这个宏和 thunk-let 很像，不同的是，这个宏在绑定变量时允许引用之前的绑定。使用这个宏需要 lexical-binding。

```
(thunk-let* ((x (prog2 (message "Calculating x...")
                    (+ 1 1)
                  (message "Finished calculating x")))
             (y (prog2 (message "Calculating y...")
                    (+ x 1)
                  (message "Finished calculating y")))
             (z (prog2 (message "Calculating z...")
                    (+ y 1)
                  (message "Finished calculating z")))
             (a (prog2 (message "Calculating a...")
                    (+ z 1)
                  (message "Finished calculating a"))))
  (* z x))

-| Calculating z...
-| Calculating y...
-| Calculating x...
-| Finished calculating x
-| Finished calculating y
-| Finished calculating z
⇒ 8
```

thunk-let 和 thunk-let\* 都隐式地使用了 thunks：它们的宏展开会创建一些辅助符号，然后将这些辅助符号绑定到被thunks包裹的表达式。body 中 所有对原变量的引用都会被一个表达式替代，这个表达式由 thunk-force 和 作为参数的辅助符号。因此，任何使用 thunk-let 或 thunk-let\* 的代码都可以用 thunks 重写，不过在大多数时候，使用这些宏会比显式地调用 thunks 更优雅。


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://emacs-lisp.ivory.cafe/qiu-zhi/yan-chi-yun-hang.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
