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 更优雅。

最后更新于