diff options
| author | Michael Heerdegen | 2017-11-02 18:45:34 +0100 |
|---|---|---|
| committer | Michael Heerdegen | 2017-12-01 08:54:05 +0100 |
| commit | cc58d4de56e362f5e017d0607986b2962ee47fc1 (patch) | |
| tree | 3b2427fc07973dd598424ed185b5a36bc0d69be9 /doc | |
| parent | ef183144add2b92359a9ade2ec0b28681b26956b (diff) | |
| download | emacs-cc58d4de56e362f5e017d0607986b2962ee47fc1.tar.gz emacs-cc58d4de56e362f5e017d0607986b2962ee47fc1.zip | |
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')
| -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 | |||
| 455 | the program). | 455 | the program). |
| 456 | * Backquote:: Easier construction of list structure. | 456 | * Backquote:: Easier construction of list structure. |
| 457 | * Eval:: How to invoke the Lisp interpreter explicitly. | 457 | * Eval:: How to invoke the Lisp interpreter explicitly. |
| 458 | * Deferred Eval:: Deferred and lazy evaluation of forms. | ||
| 458 | 459 | ||
| 459 | Kinds of Forms | 460 | Kinds of Forms |
| 460 | 461 | ||
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}. | |||
| 20 | 20 | ||
| 21 | @ifnottex | 21 | @ifnottex |
| 22 | @menu | 22 | @menu |
| 23 | * Intro Eval:: Evaluation in the scheme of things. | 23 | * Intro Eval:: Evaluation in the scheme of things. |
| 24 | * Forms:: How various sorts of objects are evaluated. | 24 | * Forms:: How various sorts of objects are evaluated. |
| 25 | * Quoting:: Avoiding evaluation (to put constants in the program). | 25 | * Quoting:: Avoiding evaluation (to put constants in the program). |
| 26 | * Backquote:: Easier construction of list structure. | 26 | * Backquote:: Easier construction of list structure. |
| 27 | * Eval:: How to invoke the Lisp interpreter explicitly. | 27 | * Eval:: How to invoke the Lisp interpreter explicitly. |
| 28 | * Deferred Eval:: Deferred and lazy evaluation of forms. | ||
| 28 | @end menu | 29 | @end menu |
| 29 | 30 | ||
| 30 | @node Intro Eval | 31 | @node Intro Eval |
| @@ -877,3 +878,115 @@ particular elements, like this: | |||
| 877 | @end group | 878 | @end group |
| 878 | @end example | 879 | @end example |
| 879 | @end defvar | 880 | @end defvar |
| 881 | |||
| 882 | @node Deferred Eval | ||
| 883 | @section Deferred and Lazy Evaluation | ||
| 884 | |||
| 885 | @cindex deferred evaluation | ||
| 886 | @cindex lazy evaluation | ||
| 887 | |||
| 888 | |||
| 889 | Sometimes it is useful to delay the evaluation of an expression, for | ||
| 890 | example if you want to avoid to perform a time-consuming calculation | ||
| 891 | in the case that it turns out that the result is not needed in the | ||
| 892 | future of the program. Therefore, the @file{thunk} library provides | ||
| 893 | the following functions and macros: | ||
| 894 | |||
| 895 | @cindex thunk | ||
| 896 | @defmac thunk-delay forms@dots{} | ||
| 897 | Return a @dfn{thunk} for evaluating the @var{forms}. A thunk is a | ||
| 898 | closure (@pxref{Closures}) that inherits the lexical enviroment of the | ||
| 899 | @code{thunk-delay} call. Using this macro requires | ||
| 900 | @code{lexical-binding}. | ||
| 901 | @end defmac | ||
| 902 | |||
| 903 | @defun thunk-force thunk | ||
| 904 | Force @var{thunk} to perform the evaluation of the forms specified in | ||
| 905 | the @code{thunk-delay} that created the thunk. The result of the | ||
| 906 | evaluation of the last form is returned. The @var{thunk} also | ||
| 907 | ``remembers'' that it has been forced: Any further calls of | ||
| 908 | @code{thunk-force} with the same @var{thunk} will just return the same | ||
| 909 | result without evaluating the forms again. | ||
| 910 | @end defun | ||
| 911 | |||
| 912 | @defmac thunk-let (bindings@dots{}) forms@dots{} | ||
| 913 | This macro is analogous to @code{let} but creates ``lazy'' variable | ||
| 914 | bindings. Any binding has the form @w{@code{(@var{symbol} | ||
| 915 | @var{value-form})}}. Unlike @code{let}, the evaluation of any | ||
| 916 | @var{value-form} is deferred until the binding of the according | ||
| 917 | @var{symbol} is used for the first time when evaluating the | ||
| 918 | @var{forms}. Any @var{value-form} is evaluated at most once. Using | ||
| 919 | this macro requires @code{lexical-binding}. | ||
| 920 | @end defmac | ||
| 921 | |||
| 922 | Example: | ||
| 923 | |||
| 924 | @example | ||
| 925 | @group | ||
| 926 | (defun f (number) | ||
| 927 | (thunk-let ((derived-number | ||
| 928 | (progn (message "Calculating 1 plus 2 times %d" number) | ||
| 929 | (1+ (* 2 number))))) | ||
| 930 | (if (> number 10) | ||
| 931 | derived-number | ||
| 932 | number))) | ||
| 933 | @end group | ||
| 934 | |||
| 935 | @group | ||
| 936 | (f 5) | ||
| 937 | @result{} 5 | ||
| 938 | @end group | ||
| 939 | |||
| 940 | @group | ||
| 941 | (f 12) | ||
| 942 | @print{} Calculating 1 plus 2 times 12 | ||
| 943 | @result{} 25 | ||
| 944 | @end group | ||
| 945 | |||
| 946 | @end example | ||
| 947 | |||
| 948 | Because of the special nature of lazily bound variables, it is an error | ||
| 949 | to set them (e.g.@: with @code{setq}). | ||
| 950 | |||
| 951 | |||
| 952 | @defmac thunk-let* (bindings@dots{}) forms@dots{} | ||
| 953 | This is like @code{thunk-let} but any expression in @var{bindings} is allowed | ||
| 954 | to refer to preceding bindings in this @code{thunk-let*} form. Using | ||
| 955 | this macro requires @code{lexical-binding}. | ||
| 956 | @end defmac | ||
| 957 | |||
| 958 | @example | ||
| 959 | @group | ||
| 960 | (thunk-let* ((x (prog2 (message "Calculating x...") | ||
| 961 | (+ 1 1) | ||
| 962 | (message "Finished calculating x"))) | ||
| 963 | (y (prog2 (message "Calculating y...") | ||
| 964 | (+ x 1) | ||
| 965 | (message "Finished calculating y"))) | ||
| 966 | (z (prog2 (message "Calculating z...") | ||
| 967 | (+ y 1) | ||
| 968 | (message "Finished calculating z"))) | ||
| 969 | (a (prog2 (message "Calculating a...") | ||
| 970 | (+ z 1) | ||
| 971 | (message "Finished calculating a")))) | ||
| 972 | (* z x)) | ||
| 973 | |||
| 974 | @print{} Calculating z... | ||
| 975 | @print{} Calculating y... | ||
| 976 | @print{} Calculating x... | ||
| 977 | @print{} Finished calculating x | ||
| 978 | @print{} Finished calculating y | ||
| 979 | @print{} Finished calculating z | ||
| 980 | @result{} 8 | ||
| 981 | |||
| 982 | @end group | ||
| 983 | @end example | ||
| 984 | |||
| 985 | @code{thunk-let} and @code{thunk-let*} use thunks implicitly: their | ||
| 986 | expansion creates helper symbols and binds them to thunks wrapping the | ||
| 987 | binding expressions. All references to the original variables in the | ||
| 988 | body @var{forms} are then replaced by an expression that calls | ||
| 989 | @code{thunk-force} with the according helper variable as the argument. | ||
| 990 | So, any code using @code{thunk-let} or @code{thunk-let*} could be | ||
| 991 | rewritten to use thunks, but in many cases using these macros results | ||
| 992 | in nicer code than using thunks explicitly. | ||