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 /lisp | |
| 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 'lisp')
| -rw-r--r-- | lisp/emacs-lisp/thunk.el | 59 |
1 files changed, 59 insertions, 0 deletions
diff --git a/lisp/emacs-lisp/thunk.el b/lisp/emacs-lisp/thunk.el index 371d10444b2..895fa86722d 100644 --- a/lisp/emacs-lisp/thunk.el +++ b/lisp/emacs-lisp/thunk.el | |||
| @@ -41,6 +41,10 @@ | |||
| 41 | ;; following: | 41 | ;; following: |
| 42 | ;; | 42 | ;; |
| 43 | ;; (thunk-force delayed) | 43 | ;; (thunk-force delayed) |
| 44 | ;; | ||
| 45 | ;; This file also defines macros `thunk-let' and `thunk-let*' that are | ||
| 46 | ;; analogous to `let' and `let*' but provide lazy evaluation of | ||
| 47 | ;; bindings by using thunks implicitly (i.e. in the expansion). | ||
| 44 | 48 | ||
| 45 | ;;; Code: | 49 | ;;; Code: |
| 46 | 50 | ||
| @@ -71,5 +75,60 @@ with the same DELAYED argument." | |||
| 71 | "Return non-nil if DELAYED has been evaluated." | 75 | "Return non-nil if DELAYED has been evaluated." |
| 72 | (funcall delayed t)) | 76 | (funcall delayed t)) |
| 73 | 77 | ||
| 78 | (defmacro thunk-let (bindings &rest body) | ||
| 79 | "Like `let' but create lazy bindings. | ||
| 80 | |||
| 81 | BINDINGS is a list of elements of the form (SYMBOL EXPRESSION). | ||
| 82 | Any binding EXPRESSION is not evaluated before the variable | ||
| 83 | SYMBOL is used for the first time when evaluating the BODY. | ||
| 84 | |||
| 85 | It is not allowed to set `thunk-let' or `thunk-let*' bound | ||
| 86 | variables. | ||
| 87 | |||
| 88 | Using `thunk-let' and `thunk-let*' requires `lexical-binding'." | ||
| 89 | (declare (indent 1) (debug let)) | ||
| 90 | (cl-callf2 mapcar | ||
| 91 | (lambda (binding) | ||
| 92 | (pcase binding | ||
| 93 | (`(,(pred symbolp) ,_) binding) | ||
| 94 | (_ (signal 'error (cons "Bad binding in thunk-let" | ||
| 95 | (list binding)))))) | ||
| 96 | bindings) | ||
| 97 | (cl-callf2 mapcar | ||
| 98 | (pcase-lambda (`(,var ,binding)) | ||
| 99 | (list (make-symbol (concat (symbol-name var) "-thunk")) | ||
| 100 | var binding)) | ||
| 101 | bindings) | ||
| 102 | `(let ,(mapcar | ||
| 103 | (pcase-lambda (`(,thunk-var ,_var ,binding)) | ||
| 104 | `(,thunk-var (thunk-delay ,binding))) | ||
| 105 | bindings) | ||
| 106 | (cl-symbol-macrolet | ||
| 107 | ,(mapcar (pcase-lambda (`(,thunk-var ,var ,_binding)) | ||
| 108 | `(,var (thunk-force ,thunk-var))) | ||
| 109 | bindings) | ||
| 110 | ,@body))) | ||
| 111 | |||
| 112 | (defmacro thunk-let* (bindings &rest body) | ||
| 113 | "Like `let*' but create lazy bindings. | ||
| 114 | |||
| 115 | BINDINGS is a list of elements of the form (SYMBOL EXPRESSION). | ||
| 116 | Any binding EXPRESSION is not evaluated before the variable | ||
| 117 | SYMBOL is used for the first time when evaluating the BODY. | ||
| 118 | |||
| 119 | It is not allowed to set `thunk-let' or `thunk-let*' bound | ||
| 120 | variables. | ||
| 121 | |||
| 122 | Using `thunk-let' and `thunk-let*' requires `lexical-binding'." | ||
| 123 | (declare (indent 1) (debug let)) | ||
| 124 | (cl-reduce | ||
| 125 | (lambda (expr binding) `(thunk-let (,binding) ,expr)) | ||
| 126 | (nreverse bindings) | ||
| 127 | :initial-value (macroexp-progn body))) | ||
| 128 | |||
| 129 | ;; (defalias 'lazy-let #'thunk-let) | ||
| 130 | ;; (defalias 'lazy-let* #'thunk-let*) | ||
| 131 | |||
| 132 | |||
| 74 | (provide 'thunk) | 133 | (provide 'thunk) |
| 75 | ;;; thunk.el ends here | 134 | ;;; thunk.el ends here |