diff options
author | Michael Heerdegen <michael_heerdegen@web.de> | 2017-11-02 18:45:34 +0100 |
---|---|---|
committer | Michael Heerdegen <michael_heerdegen@web.de> | 2017-12-01 08:54:05 +0100 |
commit | cc58d4de56e362f5e017d0607986b2962ee47fc1 (patch) | |
tree | 3b2427fc07973dd598424ed185b5a36bc0d69be9 /doc/lispref | |
parent | ef183144add2b92359a9ade2ec0b28681b26956b (diff) | |
download | emacs-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')
-rw-r--r-- | doc/lispref/elisp.texi | 1 | ||||
-rw-r--r-- | doc/lispref/eval.texi | 123 |
2 files changed, 119 insertions, 5 deletions
diff --git a/doc/lispref/elisp.texi b/doc/lispref/elisp.texi index c7525945845..a271749e044 100644 --- a/doc/lispref/elisp.texi +++ b/doc/lispref/elisp.texi @@ -455,6 +455,7 @@ Evaluation the program). * Backquote:: Easier construction of list structure. * Eval:: How to invoke the Lisp interpreter explicitly. +* Deferred Eval:: Deferred and lazy evaluation of forms. Kinds of Forms 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. |