summaryrefslogtreecommitdiff
path: root/doc/lispref/eval.texi
diff options
context:
space:
mode:
authorMichael Heerdegen <michael_heerdegen@web.de>2017-11-02 18:45:34 +0100
committerMichael Heerdegen <michael_heerdegen@web.de>2017-12-01 08:54:05 +0100
commitcc58d4de56e362f5e017d0607986b2962ee47fc1 (patch)
tree3b2427fc07973dd598424ed185b5a36bc0d69be9 /doc/lispref/eval.texi
parentef183144add2b92359a9ade2ec0b28681b26956b (diff)
downloademacs-cc58d4de56e362f5e017d0607986b2962ee47fc1.tar.gz
Add macros `thunk-let' and `thunk-let*'
* lisp/emacs-lisp/thunk.el (thunk-let, thunk-let*): New macros. * test/lisp/emacs-lisp/thunk-tests.el: (thunk-let-basic-test, thunk-let*-basic-test) (thunk-let-bound-vars-cant-be-set-test) (thunk-let-laziness-test, thunk-let*-laziness-test) (thunk-let-bad-binding-test): New tests for `thunk-let' and `thunk-let*. * doc/lispref/eval.texi (Deferred Eval): New section. * doc/lispref/elisp.texi: Update menu.
Diffstat (limited to 'doc/lispref/eval.texi')
-rw-r--r--doc/lispref/eval.texi123
1 files changed, 118 insertions, 5 deletions
diff --git a/doc/lispref/eval.texi b/doc/lispref/eval.texi
index 064fca22ff5..74fefdb71bc 100644
--- a/doc/lispref/eval.texi
+++ b/doc/lispref/eval.texi
@@ -20,11 +20,12 @@ function @code{eval}.
@ifnottex
@menu
-* Intro Eval:: Evaluation in the scheme of things.
-* Forms:: How various sorts of objects are evaluated.
-* Quoting:: Avoiding evaluation (to put constants in the program).
-* Backquote:: Easier construction of list structure.
-* Eval:: How to invoke the Lisp interpreter explicitly.
+* Intro Eval:: Evaluation in the scheme of things.
+* Forms:: How various sorts of objects are evaluated.
+* Quoting:: Avoiding evaluation (to put constants in the program).
+* Backquote:: Easier construction of list structure.
+* Eval:: How to invoke the Lisp interpreter explicitly.
+* Deferred Eval:: Deferred and lazy evaluation of forms.
@end menu
@node Intro Eval
@@ -877,3 +878,115 @@ particular elements, like this:
@end group
@end example
@end defvar
+
+@node Deferred Eval
+@section Deferred and Lazy Evaluation
+
+@cindex deferred evaluation
+@cindex lazy evaluation
+
+
+ Sometimes it is useful to delay the evaluation of an expression, for
+example if you want to avoid to perform a time-consuming calculation
+in the case that it turns out that the result is not needed in the
+future of the program. Therefore, the @file{thunk} library provides
+the following functions and macros:
+
+@cindex thunk
+@defmac thunk-delay forms@dots{}
+Return a @dfn{thunk} for evaluating the @var{forms}. A thunk is a
+closure (@pxref{Closures}) that inherits the lexical enviroment of the
+@code{thunk-delay} call. Using this macro requires
+@code{lexical-binding}.
+@end defmac
+
+@defun thunk-force thunk
+Force @var{thunk} to perform the evaluation of the forms specified in
+the @code{thunk-delay} that created the thunk. The result of the
+evaluation of the last form is returned. The @var{thunk} also
+``remembers'' that it has been forced: Any further calls of
+@code{thunk-force} with the same @var{thunk} will just return the same
+result without evaluating the forms again.
+@end defun
+
+@defmac thunk-let (bindings@dots{}) forms@dots{}
+This macro is analogous to @code{let} but creates ``lazy'' variable
+bindings. Any binding has the form @w{@code{(@var{symbol}
+@var{value-form})}}. Unlike @code{let}, the evaluation of any
+@var{value-form} is deferred until the binding of the according
+@var{symbol} is used for the first time when evaluating the
+@var{forms}. Any @var{value-form} is evaluated at most once. Using
+this macro requires @code{lexical-binding}.
+@end defmac
+
+Example:
+
+@example
+@group
+(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)))
+@end group
+
+@group
+(f 5)
+@result{} 5
+@end group
+
+@group
+(f 12)
+@print{} Calculating 1 plus 2 times 12
+@result{} 25
+@end group
+
+@end example
+
+Because of the special nature of lazily bound variables, it is an error
+to set them (e.g.@: with @code{setq}).
+
+
+@defmac thunk-let* (bindings@dots{}) forms@dots{}
+This is like @code{thunk-let} but any expression in @var{bindings} is allowed
+to refer to preceding bindings in this @code{thunk-let*} form. Using
+this macro requires @code{lexical-binding}.
+@end defmac
+
+@example
+@group
+(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))
+
+@print{} Calculating z...
+@print{} Calculating y...
+@print{} Calculating x...
+@print{} Finished calculating x
+@print{} Finished calculating y
+@print{} Finished calculating z
+@result{} 8
+
+@end group
+@end example
+
+@code{thunk-let} and @code{thunk-let*} 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} are then replaced by an expression that calls
+@code{thunk-force} with the according helper variable as the argument.
+So, any code using @code{thunk-let} or @code{thunk-let*} could be
+rewritten to use thunks, but in many cases using these macros results
+in nicer code than using thunks explicitly.