aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorMichael Heerdegen2017-11-02 18:45:34 +0100
committerMichael Heerdegen2017-12-01 08:54:05 +0100
commitcc58d4de56e362f5e017d0607986b2962ee47fc1 (patch)
tree3b2427fc07973dd598424ed185b5a36bc0d69be9 /lisp
parentef183144add2b92359a9ade2ec0b28681b26956b (diff)
downloademacs-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.el59
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
81BINDINGS is a list of elements of the form (SYMBOL EXPRESSION).
82Any binding EXPRESSION is not evaluated before the variable
83SYMBOL is used for the first time when evaluating the BODY.
84
85It is not allowed to set `thunk-let' or `thunk-let*' bound
86variables.
87
88Using `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
115BINDINGS is a list of elements of the form (SYMBOL EXPRESSION).
116Any binding EXPRESSION is not evaluated before the variable
117SYMBOL is used for the first time when evaluating the BODY.
118
119It is not allowed to set `thunk-let' or `thunk-let*' bound
120variables.
121
122Using `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