10.6 延迟求值与惰性求值

有时候,推迟表达式的求值是很有用的。例如:如果后续程序中可能根本用不到某个结果,你就可以避免执行一次耗时的计算。 thunk 库提供了下面这些函数和宏,来支持这种 延迟求值(deferred evaluation)

Macro: thunk-delay forms…

返回一个用于对 forms 进行求值的 惰性计算对象(thunk)。thunk 是一个闭包(see 闭包),它会继承 thunk-delay 调用处的词法环境。使用该宏需要开启 lexical-binding(词法绑定)。

Function: thunk-force thunk

强制执行 thunk,对创建该 thunk 的 thunk-delay 中指定的表达式进行求值。函数会返回最后一个表达式的求值结果。该 thunk 还会 “记住(remembers)”自己已被执行:后续对同一个 thunk 调用 thunk-force 时,只会直接返回相同结果,而不会再次求值这些表达式。

Macro: thunk-let (bindings…) forms…

该宏与 let 类似,但会创建 “惰性(lazy)” 变量绑定。每个绑定的形式为 (symbol value-form)。与 let 不同的是:value-form 的求值会被推迟,直到在对 forms 求值时,第一次使用对应符号 symbol 的绑定才会触发求值。每个 value-form 最多只会被求值一次。使用该宏需要开启 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 类似,但允许 bindings 中的表达式引用当前 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-letthunk-let* 会隐式使用 thunk:它们在展开时会创建辅助符号,并将这些符号绑定到包裹了绑定表达式的 thunk 上。函数体 forms 中对原变量的所有引用,都会被替换成以对应辅助变量为参数调用 thunk-force 的表达式。 因此,任何使用 thunk-letthunk-let* 的代码都可以改写成直接使用 thunk,但在很多场景下,使用这些宏写出的代码比显式使用 thunk 更简洁优雅。


emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© 2025 Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike