From: <Joe...@t-...> - 2017-12-20 17:35:54
|
Hi, Sam wrote: >"lazy-binding": bind the variable but not initialize its value. until it is explicitly set, >accessing it reaches up in the environment. Interesting challenge :-) > This would require something like `lazy-let` with the following test case: --8<---------------cut here---------------start------------->8--- (let ((a 1)) (lazy-let (a b) (print a) ; prints 1 (print b) ; error - unbound variable (setq a 10) ; inner binding of a is activated (print a) ; prints 10 (setq b 22)) ; binding of b is activated (print b) ; error - unbound variable (print a)) ; prints 1 --8<---------------cut here---------------end--------------->8--- >Alternatively, `lazy-let` can be implemented as something like > (let ((a (if (boundp 'a) a (sys::%unbound)))) ...) Certainly not, BOUNDP would only work with variables declared special. Perhaps SYMBOL-MACROLET? But that won't work either, because the problem remains that once `a becomes a symbol-macro, one cannot express anymore "let me access `a from the outer environment". Didn't somebody once post a bug report about similar infinite macro expansion about regular macros? This makes me remember that there have been several past attempts at trying to make the environment-access functions of CLtL2 fly. But Google turned up few references, I must have been dreaming. :-( http://clast.sourceforge.net/ Hmm, there's perhaps nothing that another level of delayed evaluation in order to get the desired scoping couldn't solve, so here it is: (defmacro lazy-let1 ((var) &body body) (let ((shadow (gensym (symbol-name var)))) `(let ((,shadow 'unbound));(sys::%unbound) (flet ((access-a () (if (eq ,shadow 'unbound) ,var ,shadow)) ((setf access-a) (x) (setf ,shadow x))) (symbol-macrolet ((,var (access-a))) .,body))))) ; bonus point 0: Add more required gensyms ; bonus point 1: Support a list of variables as per Sam's specification ; bonus point 2: See if LET can work with clisp's %unbound trick ; bonus point 3.5: See if you can make it work with special variables... (let ((a 1)) (lazy-let1 (a) (print a) ; prints 1 (setq a 10) ; inner binding of a is activated (print a)) ; prints 10 (print a)) ; prints 1 Regards, Jörg |