blob: 18d7dc2f0b27455a16c41364bffb864dbe80ce7b (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
|
<h3 class="section">Deferred and Lazy Evaluation</h3> <p>Sometimes it is useful to delay the evaluation of an expression, for example if you want to avoid performing a time-consuming calculation if it turns out that the result is not needed in the future of the program. The <samp>thunk</samp> library provides the following functions and macros to support such <em>deferred evaluation</em>: </p> <dl> <dt id="thunk-delay">Macro: <strong>thunk-delay</strong> <em>forms…</em>
</dt> <dd><p>Return a <em>thunk</em> for evaluating the <var>forms</var>. A thunk is a closure (see <a href="closures">Closures</a>) that inherits the lexical environment of the <code>thunk-delay</code> call. Using this macro requires <code>lexical-binding</code>. </p></dd>
</dl> <dl> <dt id="thunk-force">Function: <strong>thunk-force</strong> <em>thunk</em>
</dt> <dd><p>Force <var>thunk</var> to perform the evaluation of the forms specified in the <code>thunk-delay</code> that created the thunk. The result of the evaluation of the last form is returned. The <var>thunk</var> also “remembers” that it has been forced: Any further calls of <code>thunk-force</code> with the same <var>thunk</var> will just return the same result without evaluating the forms again. </p></dd>
</dl> <dl> <dt id="thunk-let">Macro: <strong>thunk-let</strong> <em>(bindings…) forms…</em>
</dt> <dd><p>This macro is analogous to <code>let</code> but creates “lazy” variable bindings. Any binding has the form <code>(<var>symbol</var> <var><span class="nolinebreak">value-form</span></var>)</code>. Unlike <code>let</code>, the evaluation of any <var>value-form</var> is deferred until the binding of the according <var>symbol</var> is used for the first time when evaluating the <var>forms</var>. Any <var>value-form</var> is evaluated at most once. Using this macro requires <code>lexical-binding</code>. </p></dd>
</dl> <p>Example: </p> <div class="example"> <pre class="example">(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)))
</pre>
<pre class="example">(f 5)
⇒ 5
</pre>
<pre class="example">(f 12)
-| Calculating 1 plus 2 times 12
⇒ 25
</pre>
</div> <p>Because of the special nature of lazily bound variables, it is an error to set them (e.g. with <code>setq</code>). </p> <dl> <dt id="thunk-let*">Macro: <strong>thunk-let*</strong> <em>(bindings…) forms…</em>
</dt> <dd><p>This is like <code>thunk-let</code> but any expression in <var>bindings</var> is allowed to refer to preceding bindings in this <code>thunk-let*</code> form. Using this macro requires <code>lexical-binding</code>. </p></dd>
</dl> <div class="example"> <pre class="example">(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
</pre>
</div> <p><code>thunk-let</code> and <code>thunk-let*</code> use thunks implicitly: their expansion creates helper symbols and binds them to thunks wrapping the binding expressions. All references to the original variables in the body <var>forms</var> are then replaced by an expression that calls <code>thunk-force</code> with the according helper variable as the argument. So, any code using <code>thunk-let</code> or <code>thunk-let*</code> could be rewritten to use thunks, but in many cases using these macros results in nicer code than using thunks explicitly. </p><div class="_attribution">
<p class="_attribution-p">
Copyright © 1990-1996, 1998-2022 Free Software Foundation, Inc. <br>Licensed under the GNU GPL license.<br>
<a href="https://www.gnu.org/software/emacs/manual/html_node/elisp/Deferred-Eval.html" class="_attribution-link">https://www.gnu.org/software/emacs/manual/html_node/elisp/Deferred-Eval.html</a>
</p>
</div>
|