* Macro expansion: Why doesn't the invoked macro see (let (variables)) from the invoking one? @ 2012-02-08 17:26 Alan Mackenzie 2012-02-08 17:46 ` Macro expansion: Why doesn't the invoked macro see (let (variables))from " Drew Adams 2012-02-08 18:05 ` Macro expansion: Why doesn't the invoked macro see (let (variables)) from " Tassilo Horn 0 siblings, 2 replies; 9+ messages in thread From: Alan Mackenzie @ 2012-02-08 17:26 UTC (permalink / raw) To: emacs-devel Hello, Emacs. One macro FOO binds a let variable, then invokes another macro BAR. BAR doesn't see this let variable. Why not? Is there anything I can do about this? (defmacro BAR () (message (if (boundp 'asdf) "asdf" "no asdf")) '(message "bar")) (defmacro FOO () (let (asdf) `(BAR))) -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 9+ messages in thread
* RE: Macro expansion: Why doesn't the invoked macro see (let (variables))from the invoking one? 2012-02-08 17:26 Macro expansion: Why doesn't the invoked macro see (let (variables)) from the invoking one? Alan Mackenzie @ 2012-02-08 17:46 ` Drew Adams 2012-02-08 19:28 ` Alan Mackenzie 2012-02-08 18:05 ` Macro expansion: Why doesn't the invoked macro see (let (variables)) from " Tassilo Horn 1 sibling, 1 reply; 9+ messages in thread From: Drew Adams @ 2012-02-08 17:46 UTC (permalink / raw) To: 'Alan Mackenzie', emacs-devel > (defmacro BAR () > (message (if (boundp 'asdf) "asdf" "no asdf")) > '(message "bar")) > > (defmacro FOO () (let (asdf) `(BAR))) > > One macro FOO binds a let variable, then invokes another > macro BAR. BAR doesn't see this let variable. Why not? That `let' binding is evaluated only when FOO is expanded. It is not part of the resulting expansion (which is then evaluated). > Is there anything I can do about this? 1. Don't use side effects in the macro definition. A macro just produces a first result (the expansion), which is then evaluated to produce the final result. Anything you want to be seen during that latter evaluation needs to be part of the expansion itself. The first call to `message' in macro BAR has no effect when the expansion of BAR is evaluated (it is not part of the expansion). `(BAR)' is expanded to `(message "bar")', which is then evaluated to "bar", which is returned. 2. You might be looking for something like this (dunno): (defmacro FOO () `(let (asdf) ,(BAR))) When `(FOO)' is expanded, the expansion includes a `let' binding. This is the result of `(macroexpand '(FOO))': (let (asdf) "bar") Not sure what you're really trying to do, though. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Macro expansion: Why doesn't the invoked macro see (let (variables))from the invoking one? 2012-02-08 17:46 ` Macro expansion: Why doesn't the invoked macro see (let (variables))from " Drew Adams @ 2012-02-08 19:28 ` Alan Mackenzie 2012-02-08 19:52 ` Stefan Monnier 2012-02-08 20:16 ` Andreas Schwab 0 siblings, 2 replies; 9+ messages in thread From: Alan Mackenzie @ 2012-02-08 19:28 UTC (permalink / raw) To: Drew Adams; +Cc: emacs-devel Hello, Drew! On Wed, Feb 08, 2012 at 09:46:45AM -0800, Drew Adams wrote: > > (defmacro BAR () > > (message (if (boundp 'asdf) "asdf" "no asdf")) > > '(message "bar")) > > (defmacro FOO () (let (asdf) `(BAR))) > > One macro FOO binds a let variable, then invokes another > > macro BAR. BAR doesn't see this let variable. Why not? > That `let' binding is evaluated only when FOO is expanded. This is what I want. > It is not part of the resulting expansion (which is then evaluated). > > Is there anything I can do about this? > 1. Don't use side effects in the macro definition. I need side effects during macro expansion (see below). > 2. You might be looking for something like this (dunno): > (defmacro FOO () `(let (asdf) ,(BAR))) > When `(FOO)' is expanded, the expansion includes a `let' binding. > This is the result of `(macroexpand '(FOO))': > (let (asdf) "bar") > Not sure what you're really trying to do, though. OK, here it is in grisly detail. I want to amend define-minor-mode so that the position of calling the mode hooks can be specified by d-m-m's invoker. To do this, the invoker should insert the macro (run-hooks-here) at the appropriate place. During its expansion, run-hooks-here needs to set a flag for define-minor-mode meaning "hook expansion already done". Should this flag not get set, d-m-m inserts the hook calls in the default place. What I was trying to do looks like this: (defmacro run-hooks-here () (setq hooks-called t) <================= flag variable `(run-hooks ',hook (if ,mode ',hook-on ',hook-off))) (defmacro define-minor-mode (....) .... (let (... hooks-run) .... ,@body <================= expand invoker's forms <====== There may be (run-hooks-here) here. ,@(unless hooks-run `((run-hooks-here))) <========= test flag Should run-hooks-here appear in ,@body, it should inhibit the later expansion of r-h-h. ######################################################################## So, we've got a dynamically scoped language. run-hooks-here is invoked from define-minor-mode. A variable let-bound in the latter should be dynamically available in the former. It isn't. What am I missing here? -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Macro expansion: Why doesn't the invoked macro see (let (variables))from the invoking one? 2012-02-08 19:28 ` Alan Mackenzie @ 2012-02-08 19:52 ` Stefan Monnier 2012-02-08 20:09 ` Alan Mackenzie 2012-02-08 20:16 ` Andreas Schwab 1 sibling, 1 reply; 9+ messages in thread From: Stefan Monnier @ 2012-02-08 19:52 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Drew Adams, emacs-devel > (defmacro run-hooks-here () > (setq hooks-called t) <================= flag variable > `(run-hooks ',hook (if ,mode ',hook-on ',hook-off))) > (defmacro define-minor-mode (....) > .... > (let (... hooks-run) > .... > ,@body <================= expand invoker's forms This comment is wrong: ",@body" just plugs in the `body' without macro-expanding it. > <====== There may be (run-hooks-here) here. > ,@(unless hooks-run `((run-hooks-here))) <========= test flag You can do that, but you then need to make sure the `body' gets macro-expanded while the `let' is live, i.e. during the expansion of the call to `define-minor-mode'. You can do it with something like (defmacro define-minor-mode (....) .... (let (... hooks-run) .... ,@(macroexpand-all body) <================= expand invoker's forms <====== There may be (run-hooks-here) here. ,@(unless hooks-run `((run-hooks-here))) <========= test flag But note that this counts as ugly. We use such tricks in cl-macs.el to figure out whether `body' uses `return-from' within a `block' (in order to optimize away the `catch' that's otherwise needed), but it's ugly, inefficient, and brittle. An :after-hook (or :late-code or some other name you prefer) is much better in this regard. Stefan ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Macro expansion: Why doesn't the invoked macro see (let (variables))from the invoking one? 2012-02-08 19:52 ` Stefan Monnier @ 2012-02-08 20:09 ` Alan Mackenzie 2012-02-10 5:23 ` PJ Weisberg 0 siblings, 1 reply; 9+ messages in thread From: Alan Mackenzie @ 2012-02-08 20:09 UTC (permalink / raw) To: Stefan Monnier; +Cc: Drew Adams, emacs-devel On Wed, Feb 08, 2012 at 02:52:45PM -0500, Stefan Monnier wrote: > > (defmacro run-hooks-here () > > (setq hooks-called t) <================= flag variable > > `(run-hooks ',hook (if ,mode ',hook-on ',hook-off))) > > (defmacro define-minor-mode (....) > > .... > > (let (... hooks-run) > > .... > > ,@body <================= expand invoker's forms > This comment is wrong: ",@body" just plugs in the `body' without > macro-expanding it. > > <====== There may be (run-hooks-here) here. > > ,@(unless hooks-run `((run-hooks-here))) <========= test flag > You can do that, but you then need to make sure the `body' gets > macro-expanded while the `let' is live, i.e. during the expansion of the > call to `define-minor-mode'. Surely it should be done that way anyway? I think I'm beginning to get a clue, but why would expansion of macros be delayed? That seems to preclude normal healthy use of side effects. > You can do it with something like > (defmacro define-minor-mode (....) > .... > (let (... hooks-run) > .... > ,@(macroexpand-all body) <================= expand invoker's forms > <====== There may be (run-hooks-here) here. > ,@(unless hooks-run `((run-hooks-here))) <========= test flag > But note that this counts as ugly. I wouldn't disagree with that. > We use such tricks in cl-macs.el to figure out whether `body' uses > `return-from' within a `block' (in order to optimize away the `catch' > that's otherwise needed), but it's ugly, inefficient, and brittle. An > :after-hook (or :late-code or some other name you prefer) is much > better in this regard. I think you're right. Ah well. I learnt this afternoon that quoting a macro invocation '(foo-macro) doesn't stop it being expanded. I don't think that's in the elisp manual. > Stefan -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Macro expansion: Why doesn't the invoked macro see (let (variables))from the invoking one? 2012-02-08 20:09 ` Alan Mackenzie @ 2012-02-10 5:23 ` PJ Weisberg 2012-02-10 16:58 ` Alan Mackenzie 0 siblings, 1 reply; 9+ messages in thread From: PJ Weisberg @ 2012-02-10 5:23 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Stefan Monnier, Drew Adams, emacs-devel On Wed, Feb 8, 2012 at 12:09 PM, Alan Mackenzie <acm@muc.de> wrote: > I think you're right. Ah well. I learnt this afternoon that quoting a > macro invocation > > '(foo-macro) > > doesn't stop it being expanded. I don't think that's in the elisp > manual. Of course it isn't, because it's not true. Try it yourself: (defmacro foo-macro () '(message "Foo macro's code has run!")) (defmacro bar-macro (one two) `(list ,one '(foo-macro) ,two)) If you evaluate: (bar-macro "Hello" "World") You get ("Hello" (foo-macro) "World") Whereas if you changed bar-macro to: (defmacro bar-macro (one two) `(list ,one (foo-macro) ,two)) you would get: ("Hello" "Foo macro's code has run!" "World") Likewise, (foo-macro) evaluates to "Foo macro's code has run!" (and prints the message), but '(foo-macro) evaluates to (foo-macro), exactly as you would expect. -PJ Gehm's Corrollary to Clark's Law: Any technology distinguishable from magic is insufficiently advanced. ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Macro expansion: Why doesn't the invoked macro see (let (variables))from the invoking one? 2012-02-10 5:23 ` PJ Weisberg @ 2012-02-10 16:58 ` Alan Mackenzie 0 siblings, 0 replies; 9+ messages in thread From: Alan Mackenzie @ 2012-02-10 16:58 UTC (permalink / raw) To: PJ Weisberg; +Cc: Stefan Monnier, Drew Adams, emacs-devel On Thu, Feb 09, 2012 at 09:23:55PM -0800, PJ Weisberg wrote: > On Wed, Feb 8, 2012 at 12:09 PM, Alan Mackenzie <acm@muc.de> wrote: > > I think you're right. Ah well. I learnt this afternoon that quoting a > > macro invocation > > '(foo-macro) > > doesn't stop it being expanded. I don't think that's in the elisp > > manual. > Of course it isn't, because it's not true. Try it yourself: > (defmacro foo-macro () > '(message "Foo macro's code has run!")) > (defmacro bar-macro (one two) > `(list ,one '(foo-macro) ,two)) > If you evaluate: > (bar-macro "Hello" "World") > You get > ("Hello" (foo-macro) "World") > Whereas if you changed bar-macro to: > (defmacro bar-macro (one two) > `(list ,one (foo-macro) ,two)) > you would get: > ("Hello" "Foo macro's code has run!" "World") > Likewise, (foo-macro) evaluates to "Foo macro's code has run!" (and > prints the message), but '(foo-macro) evaluates to (foo-macro), > exactly as you would expect. Hmmm. I wish I could remember exactly what I saw when playing around. It was something involving macroexpand and a backquote. Ah well, I'll come across it again, sometime. Thanks for the correction. > -PJ -- Alan Mackenzie (Nuremberg, Germany). ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Macro expansion: Why doesn't the invoked macro see (let (variables))from the invoking one? 2012-02-08 19:28 ` Alan Mackenzie 2012-02-08 19:52 ` Stefan Monnier @ 2012-02-08 20:16 ` Andreas Schwab 1 sibling, 0 replies; 9+ messages in thread From: Andreas Schwab @ 2012-02-08 20:16 UTC (permalink / raw) To: Alan Mackenzie; +Cc: Drew Adams, emacs-devel Alan Mackenzie <acm@muc.de> writes: > So, we've got a dynamically scoped language. run-hooks-here is invoked > from define-minor-mode. No, run-hooks-here is not invoked, `((run-hooks-here)) is invoked, which returns '((run-hooks-here)), which is then substituted into the expansion of define-minor-mode. If you want run-hooks-here to be invoked you need to use `(,(run-hooks-here)). Andreas. -- Andreas Schwab, schwab@linux-m68k.org GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different." ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: Macro expansion: Why doesn't the invoked macro see (let (variables)) from the invoking one? 2012-02-08 17:26 Macro expansion: Why doesn't the invoked macro see (let (variables)) from the invoking one? Alan Mackenzie 2012-02-08 17:46 ` Macro expansion: Why doesn't the invoked macro see (let (variables))from " Drew Adams @ 2012-02-08 18:05 ` Tassilo Horn 1 sibling, 0 replies; 9+ messages in thread From: Tassilo Horn @ 2012-02-08 18:05 UTC (permalink / raw) To: Alan Mackenzie; +Cc: emacs-devel Alan Mackenzie <acm@muc.de> writes: Hi Alan, > One macro FOO binds a let variable, then invokes another macro BAR. > BAR doesn't see this let variable. Why not? Is there anything I can > do about this? > > (defmacro BAR () > (message (if (boundp 'asdf) "asdf" "no asdf")) > '(message "bar")) > > (defmacro FOO () > (let (asdf) > `(BAR))) It seems first (FOO) expands into (BAR) and at that time asdf is bound, but then the expansion of (BAR) is again isolated. It looks like try to create a macro that creates a different expansion depending on its context. I don't think that's a good idea anyway. Better add an explicit asdf parameter. Bye, Tassilo ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2012-02-10 16:58 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2012-02-08 17:26 Macro expansion: Why doesn't the invoked macro see (let (variables)) from the invoking one? Alan Mackenzie 2012-02-08 17:46 ` Macro expansion: Why doesn't the invoked macro see (let (variables))from " Drew Adams 2012-02-08 19:28 ` Alan Mackenzie 2012-02-08 19:52 ` Stefan Monnier 2012-02-08 20:09 ` Alan Mackenzie 2012-02-10 5:23 ` PJ Weisberg 2012-02-10 16:58 ` Alan Mackenzie 2012-02-08 20:16 ` Andreas Schwab 2012-02-08 18:05 ` Macro expansion: Why doesn't the invoked macro see (let (variables)) from " Tassilo Horn
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).