Or, the Continuing Joy of Symbol Macros
A possibly harebrained use of symbol macros to produce variables that evaluate "lazily". A short one.
Check It Out
This is your REPL
;; Boring Binding > (let* ((one (progn (print "binding one") 10)) (two (progn (print "biding two") (* one one))) (three (progn (print "binding three") 1000))) (if (zerop (random 2)) three two)) "binding one" "biding two" "binding three" 1000
This is your REPL on
;; Living Lazily > (lazy ((two (progn (print "forcing two") (* one one))) (one (progn (print "forcing one") 10)) (three (progn (print "forcing three") 1000))) (if (zerop (random 2)) three two)) "forcing two" "forcing one" 100
As was the case for with-plist, today's hidden hero is
;; Folks, tell me all the ways this will fall on its lazy face. (defmacro lazy ((&rest binding-forms) &body body) (let ((lazy-control (loop :for (name form) :in binding-forms :collect (list name form (gensym "CACHED") (gensym "FORCED"))))) `(let ,(loop :for (n frm c f) :in lazy-control :collect `(,c nil) :collect `(,f nil)) (declare (ignorable ,@(loop for (nm fm c f) :in lazy-control :collect c :collect f))) (symbol-macrolet ,(loop :for (name form cached forced) :in lazy-control :collect `(,name (if ,forced ,cached (setf ,forced t ,cached ,form)))) ,@body))))
That's all for today. Hope you enjoyed another half-baked Parenthetical Curio!