[iterate-devel] bug report
(defmacro foo () ''macro) (iter (for i from 1 to 1) (labels ((foo () 'labels)) (return (foo)))) returns MACRO, not LABELS --larry
Hi, Larry D'Anna wrote:
(defmacro foo () ''macro) (iter (for i from 1 to 1) (labels ((foo () 'labels)) (return (foo)))) returns MACRO, not LABELS
This is a known bug & problem area. It has to do with code walkers inability to interact with the lexical environment in a proper & standardized way. All code walkers implement heuristics that work more or less well, depending on their purpose (IMHO a code-walker for XREF is easier than for Iterate, because XREF need not rewrite the code). Allegro published an environment interface, but I've seen no deep discussion of it, only heard opinions (mostly about lack of suitability for other implementations). Alas, Iterate's design depends on a code walker. E.g. it needs to know that somewhere deep inside the body, there's a COLLECT clause, so that it can prepare appropriate variables. Other designs, e.g. LOOP or Scheme's eager comprehensions (SRFIxy) do not depend on a code walker. But then they reinvent control structure like WHEN, UNLESS, AND, :if etc. Is there some particular standard code which you met which results in the above problem? E.g. Iterate already special cases ignore-errors (for simplicity) and handler-bind (on CLISP). I've wondered here and then whether it should special-case CALL-NEXT-METHOD, as it might be problematic in some implementations (somebody probably has yet to write a method involving call-next-method within Iterate). Regards, Jorg Hohle
(defmacro foo () ''macro)
(iter (for i from 1 to 1) (labels ((foo () 'labels)) (return (foo))))
returns MACRO, not LABELS
this is a limitation of iterate, it's not updating the environment while walking its body (in fact it calls macroexpand with nil env, i think). this is mostly becase doing so would be platform dependent. this won't be quickly fixed, but corrent me if i'm wrong. -- attila
Attila Lendvai wrote:
(in fact it calls macroexpand with nil env, i think). No, it doesn't. this won't be quickly fixed, but corrent me if i'm wrong. No macro should call macroexpand with the nil env. That's completely wrong, in most cases. Iterate properly uses the env parameter. The env parameter is there for a purpose.
It's there so that the surrounding environment can be handled correctly, e.g. Iterate knows that in (defun or defmacro foo ...) (macrolet foo ... (flet foo ... (Iterate ...))) foo is a function, not a macro. What Iterate (and many others) cannot handle properly is local definitions within its body, e.g. (Iterate (macrolet (flet ...))) It serves nothing if Iterate would keep an internal list of local functions or macros, as it cannot communicate this list (i.e. environment) to other macros. That's why CLtL2 had AUGMENT-ENVIRONMENT. Alas, why CLtL2's environment API is not good enough is really complicated. BTW, *MACROEXPAND-HOOK* is of no help either. Regards, Jörg.
Attila Lendvai wrote:
(in fact it calls macroexpand with nil env, i think). No, it doesn't. this won't be quickly fixed, but corrent me if i'm wrong. No macro should call macroexpand with the nil env. That's completely wrong, in most cases. Iterate properly uses the env parameter. The env parameter is there for a purpose.
i was too hasty to answer misinformation, not to mention not reading the other threads first, where the discussion continued. sorry for that.
What Iterate (and many others) cannot handle properly is local definitions within its body, e.g. (Iterate (macrolet (flet ...))) It serves nothing if Iterate would keep an internal list of local functions or macros, as it cannot communicate this list (i.e. environment) to other macros. That's why CLtL2 had AUGMENT-ENVIRONMENT. Alas, why CLtL2's environment API is not good enough is really complicated. BTW, *MACROEXPAND-HOOK* is of no help either.
hm, i don't have too much knowledge about environment augmentation, but the code walker (call/cc stuff) in arnesi does seem to work. you can have a peek at lexenv.lisp, but it seems to be only a subset of the CLtL2 api, so it's probably not much help then. hth anyway, -- attila
* Attila Lendvai (attila.lendvai@gmail.com) [070812 15:39]:
(defmacro foo () ''macro)
(iter (for i from 1 to 1) (labels ((foo () 'labels)) (return (foo))))
returns MACRO, not LABELS
this is a limitation of iterate, it's not updating the environment while walking its body (in fact it calls macroexpand with nil env, i think). this is mostly becase doing so would be platform dependent.
It doesn't need to be able to update the environment because it can see for itself that foo is a function, not a macro. This is the case that cannot be handled portably: (defmacro foo () ''macro) (defmacro bar (form &environment env) (macroexpand form env)) (iter (for i from 1 to 1) (labels ((foo () 'labels)) (return (bar (foo))))) --larry
Hi, Larry D'Anna wrote:
It doesn't need to be able to update the environment because it can see for itself that foo is a function, not a macro. This is the case that cannot be handled portably:
(defmacro foo () ''macro) (defmacro bar (form &environment env) (macroexpand form env)) (iter (for i from 1 to 1) (labels ((foo () 'labels)) (return (bar (foo)))))
You're both right. In fact, I like the above "bar" macro so much that I've added a variation of it to the testsuite (not yet in Darcs). I view it as the canonical representative of a foreign macro which depends on macroexpansion and environments to work -- which no code-rewriter can provide portably (at least it's a common belief). I've been wondering whether other approaches, possibly based on two passes through the code could lead to interesting results. Or sort of CPS style, e.g. have the implementation provide the environment, as in (macroexpand `(labels ((foo ...)) (iter-continuation-macro)) env) Iter-continuation-macro would then be invoked with an environment consisting of the addition of the initial env and the foo local function. Sounds interesting, except that MACROEXPAND would stop at the LABELS form... And that would still not tell me how to walk EVAL-WHEN right (another topic). Thanks, Jorg Hohle.
participants (3)
-
Attila Lendvai
-
Hoehle, Joerg-Cyril
-
Larry D'Anna