3 ms·
I wrote the exact same macro in Clojure a couple weeks ago ! (defmacro lay [[sym expr & more-bindings] & body] (let [delay-sym (gensym (str "laid-" sym "
by GorgeRonde 8y ago
I wrote the exact same macro in Clojure a couple weeks ago !
(defmacro lay [[sym expr & more-bindings] & body]
(let [delay-sym (gensym (str "laid-" sym "-"))]
`(let [~delay-sym (delay ~expr)]
(symbol-macrolet [~sym (deref ~delay-sym)]
~@(if (empty? more-bindings)
body
`[(lay ~more-bindings ~@body)])))))
- kazinator 8y agoThat expansion strategy won't work in TXR Lisp, because if we have (let ((#:g1 (delay y))) (symacrolet ((x #:g1)) (let ((#:g2 (delay z))) (symacrolet ((y #:g2)) ...)))) the (delay y) expression is not in the scope of (symacrolet ((y #:g2)) ...). Local symbol macros are lexically scoped. They can shadow lexical variables and be shadowed by them and so on. So y in (delay y) will not be expanded there as we need it to, which we need because the initializing expressions in mlet can refer to all the variables (including their own, if they are careful). This is why the code binds all of the gensyms first, and then initializes them by assignment in a scope in which the symacrolets are all visible. Using mlet plus some lazy structure like a lazy cons (lcons) we can do useful things: 1> (set *print-circle* t) t 2> (mlet ((lc (lcons 1 lc))) lc) ;; make a circular list #1=(1 . #1#)