* Compiling a recursive macro
@ 2020-06-11 20:15 Douglas Lewan
2020-06-11 20:57 ` Stefan Monnier
2020-06-12 0:03 ` Jakub Jankiewicz
0 siblings, 2 replies; 15+ messages in thread
From: Douglas Lewan @ 2020-06-11 20:15 UTC (permalink / raw)
To: help-gnu-emacs
I'm not an expert on macros whatsoever. I apologize if this is idiotic.
I've been doing battle trying to define a recursive macro, and I'd like
it to be byte compiled. However, in the info (elisp) Compiling Macros, I
find the following:
In order for compilation of macro calls to work, the macros must
already be defined in Lisp when the calls to them are compiled.
That suggests to me that you can't compile any recursive macro. Do I
understand it correctly? If I do, then I'm curious if there's a common
style for getting around this.
Thanks.
--
,Doug
d.lewan2000@gmail.com
(908) 720 7908
If this is what winning looks like, I'd hate to see what losing is.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Compiling a recursive macro
2020-06-11 20:15 Compiling a recursive macro Douglas Lewan
@ 2020-06-11 20:57 ` Stefan Monnier
2020-06-11 21:23 ` Douglas Lewan
2020-06-11 21:27 ` Michael Heerdegen
2020-06-12 0:03 ` Jakub Jankiewicz
1 sibling, 2 replies; 15+ messages in thread
From: Stefan Monnier @ 2020-06-11 20:57 UTC (permalink / raw)
To: help-gnu-emacs
> That suggests to me that you can't compile any recursive macro.
Depends what you mean by "recursive macro".
What this prevents is to use a macro inside the definition of a macro.
Most cases of "recursive macros" instead just returns code which
itself uses that macro. In that case, there's no real recursion: the
macro just returns a list which happens to include a symbol which has
the same name as the macro. And then the macro-expander will end up
calling that macro back when it gets to macro-expanding that chunk
of code.
This works just fine (and may inf-loop, of course).
Stefan
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Compiling a recursive macro
2020-06-11 20:57 ` Stefan Monnier
@ 2020-06-11 21:23 ` Douglas Lewan
2020-06-11 21:32 ` Michael Heerdegen
2020-06-11 22:02 ` Stefan Monnier
2020-06-11 21:27 ` Michael Heerdegen
1 sibling, 2 replies; 15+ messages in thread
From: Douglas Lewan @ 2020-06-11 21:23 UTC (permalink / raw)
To: Stefan Monnier, help-gnu-emacs
On 6/11/20 4:57 PM, Stefan Monnier wrote:
>> That suggests to me that you can't compile any recursive macro.
> Depends what you mean by "recursive macro".
> What this prevents is to use a macro inside the definition of a macro.
>
> Most cases of "recursive macros" instead just returns code which
> itself uses that macro. In that case, there's no real recursion: the
> macro just returns a list which happens to include a symbol which has
> the same name as the macro. And then the macro-expander will end up
> calling that macro back when it gets to macro-expanding that chunk
> of code.
> This works just fine (and may inf-loop, of course).
It did work when not compiled. However, when compiling I got a
max-depth-exceeded error. (Forgive the paraphrasing, I'm now running a
new instance of emacs.
And, if anyone cares, I did find a work-around for the macro in
question. It had the following structure:
(defmacro mmm ()
(cond ((at-root-p)
do tree-wide stuff)
(t
(with-current-buffer root (mmm)))
Since there is never more than one level of recursion, I defined another
macro to do the tree-wide stuff first and then call that from mmm.
--
,Doug
d.lewan2000@gmail.com
(908) 720 7908
If this is what winning looks like, I'd hate to see what losing is.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Compiling a recursive macro
2020-06-11 21:23 ` Douglas Lewan
@ 2020-06-11 21:32 ` Michael Heerdegen
2020-06-11 21:38 ` Douglas Lewan
2020-06-11 22:02 ` Stefan Monnier
1 sibling, 1 reply; 15+ messages in thread
From: Michael Heerdegen @ 2020-06-11 21:32 UTC (permalink / raw)
To: help-gnu-emacs
Douglas Lewan <d.lewan2000@gmail.com> writes:
> (defmacro mmm ()
> (cond ((at-root-p)
> do tree-wide stuff)
> (t
> (with-current-buffer root (mmm)))
That really looks like this shouldn't be a macro. Why do you want this
to be a macro?
Michael.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Compiling a recursive macro
2020-06-11 21:32 ` Michael Heerdegen
@ 2020-06-11 21:38 ` Douglas Lewan
2020-06-11 21:55 ` Michael Heerdegen
0 siblings, 1 reply; 15+ messages in thread
From: Douglas Lewan @ 2020-06-11 21:38 UTC (permalink / raw)
To: help-gnu-emacs
On 6/11/20 5:32 PM, Michael Heerdegen wrote:
> Douglas Lewan <d.lewan2000@gmail.com> writes:
>
>> (defmacro mmm ()
>> (cond ((at-root-p)
>> do tree-wide stuff)
>> (t
>> (with-current-buffer root (mmm)))
> That really looks like this shouldn't be a macro. Why do you want this
> to be a macro?
The macro itself has to establish a new variable for each buffer in the
tree of buffers. It's somehow not natural (to me) to pass 'new-var to a
defun that's supposed to act like (defvar).
--
,Doug
d.lewan2000@gmail.com
(908) 720 7908
If this is what winning looks like, I'd hate to see what losing is.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Compiling a recursive macro
2020-06-11 21:38 ` Douglas Lewan
@ 2020-06-11 21:55 ` Michael Heerdegen
2020-06-11 22:21 ` Douglas Lewan
2020-06-12 2:10 ` Douglas Lewan
0 siblings, 2 replies; 15+ messages in thread
From: Michael Heerdegen @ 2020-06-11 21:55 UTC (permalink / raw)
To: help-gnu-emacs
Douglas Lewan <d.lewan2000@gmail.com> writes:
> The macro itself has to establish a new variable for each buffer in
> the tree of buffers.
Are these variables buffer-local? If not - could you use an alist with
buffers being the keys instead and save that in one variable? Why do
you want one declared variable per buffer?
Michael.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Compiling a recursive macro
2020-06-11 21:55 ` Michael Heerdegen
@ 2020-06-11 22:21 ` Douglas Lewan
2020-06-12 10:49 ` Michael Heerdegen
2020-06-12 2:10 ` Douglas Lewan
1 sibling, 1 reply; 15+ messages in thread
From: Douglas Lewan @ 2020-06-11 22:21 UTC (permalink / raw)
To: help-gnu-emacs
On 6/11/20 5:55 PM, Michael Heerdegen wrote:
> Douglas Lewan <d.lewan2000@gmail.com> writes:
>
>> The macro itself has to establish a new variable for each buffer in
>> the tree of buffers.
> Are these variables buffer-local? If not - could you use an alist with
> buffers being the keys instead and save that in one variable? Why do
> you want one declared variable per buffer?
They are buffer-local. Definition of such a variable spans the tree of
buffers in question. I suppose I could just define them in the root
buffer, but then I'd also need to use a specialized getter instead of
the variable itself. The latter definitely seems preferable to me. If
there's a way to do this with emacs lisp's natural scoping, I'm more
than happy to learn.
--
,Doug
d.lewan2000@gmail.com
(908) 720 7908
If this is what winning looks like, I'd hate to see what losing is.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Compiling a recursive macro
2020-06-11 22:21 ` Douglas Lewan
@ 2020-06-12 10:49 ` Michael Heerdegen
2020-06-12 16:11 ` Douglas Lewan
0 siblings, 1 reply; 15+ messages in thread
From: Michael Heerdegen @ 2020-06-12 10:49 UTC (permalink / raw)
To: help-gnu-emacs
Douglas Lewan <d.lewan2000@gmail.com> writes:
> They are buffer-local. Definition of such a variable spans the tree of
> buffers in question. I suppose I could just define them in the root
> buffer, but then I'd also need to use a specialized getter instead of
> the variable itself. The latter definitely seems preferable to me. If
> there's a way to do this with emacs lisp's natural scoping, I'm more
> than happy to learn.
If you want to use local variables: `make-local-variable' makes a
variable local in the current buffer, `make-variable-buffer-local'
generally; both are functions (not special forms or macros). And the
getter is `buffer-local-value'; also a function.
Michael.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Compiling a recursive macro
2020-06-12 10:49 ` Michael Heerdegen
@ 2020-06-12 16:11 ` Douglas Lewan
0 siblings, 0 replies; 15+ messages in thread
From: Douglas Lewan @ 2020-06-12 16:11 UTC (permalink / raw)
To: help-gnu-emacs
On 6/12/20 6:49 AM, Michael Heerdegen wrote:
> Douglas Lewan <d.lewan2000@gmail.com> writes:
>
>> They are buffer-local. Definition of such a variable spans the tree of
>> buffers in question. I suppose I could just define them in the root
>> buffer, but then I'd also need to use a specialized getter instead of
>> the variable itself. The latter definitely seems preferable to me. If
>> there's a way to do this with emacs lisp's natural scoping, I'm more
>> than happy to learn.
> If you want to use local variables: `make-local-variable' makes a
> variable local in the current buffer, `make-variable-buffer-local'
> generally; both are functions (not special forms or macros). And the
> getter is `buffer-local-value'; also a function.
>
> Michael.
Indeed. The macros I've written wrap (make-local-variable), but contain
logic that reflects the structure that I'm working with. The package is
intended to be generic, so expecting the user to rewrite the logic over
and over seems inappropriate.
BTW both (make-local-variable) and (make-variable-buffer-local) are
written in C, so they can have direct and transparent access to symbols.
That's a luxury that mere emacs lisp programmers don't have with functions.
--
,Doug
d.lewan2000@gmail.com
(908) 720 7908
If this is what winning looks like, I'd hate to see what losing is.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Compiling a recursive macro
2020-06-11 21:55 ` Michael Heerdegen
2020-06-11 22:21 ` Douglas Lewan
@ 2020-06-12 2:10 ` Douglas Lewan
2020-06-13 9:49 ` Michael Heerdegen
1 sibling, 1 reply; 15+ messages in thread
From: Douglas Lewan @ 2020-06-12 2:10 UTC (permalink / raw)
To: help-gnu-emacs
I managed to lose the last response to my original question, the one
with the case_ macro. Here it is for reference:
(defmacro case_ (val &rest list)
"(case value
((<items>) result1)
((<items>) result2)
[else result3])
Macro for switch case statement. It test if value is any of the item. If
item match the value it will return coresponding result expression value.
If no value match and there is else it will return that result."
(if (listp list)
(let* ((item (car list))
(first (car item))
(result (cadr item))
(rest (cdr list))
(value (gensym)))
`(let ((,value ,val))
(if (member ,value ',first)
,result
,(if (and (listp rest)
(eq (caar rest) 'else))
'xxx
(if (not (null rest))
`(case_ ,value ,@rest))))))
nil))
I did, however, manage to save the macro and, indeed, it compiles
without the max-depth-exceeded. There's an insightful difference from
what I was attempting: Instead of invoking the macro directly, here the
recursive call is inside a back-tick.
Sorry to have lost the mail. My keyboard stutters on occasion and I'm
guessing I wound up doing something distructive twice. The point is that
I'd like to thank that author.
--
,Doug
d.lewan2000@gmail.com
(908) 720 7908
If this is what winning looks like, I'd hate to see what losing is.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Compiling a recursive macro
2020-06-12 2:10 ` Douglas Lewan
@ 2020-06-13 9:49 ` Michael Heerdegen
2020-06-13 13:34 ` Jakub Jankiewicz
0 siblings, 1 reply; 15+ messages in thread
From: Michael Heerdegen @ 2020-06-13 9:49 UTC (permalink / raw)
To: Douglas Lewan; +Cc: help-gnu-emacs
Douglas Lewan <d.lewan2000@gmail.com> writes:
> I managed to lose the last response to my original question, the one
> with the case_ macro. Here it is for reference:
BTW, if you didn't know: `macroexpand-1', `macroexpand' and
`macroexpand-all' are your fried when playing with macros.
BTW2, a small problem with your posted version is that it adds one `let'
binding per branch, but only the outermost is needed:
(macroexpand-all '(case_ x ((1 2) t) (3 nil)))
==>
(let ((#1=#:g772 x))
(if (member #1# '(1 2))
t
(let ((#2=#:g773 #1#)) ;; <--- here
(if (member #2# '3)
nil nil))))
That is not harmful but a bit inelegant and inefficient.
Michael.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Compiling a recursive macro
2020-06-13 9:49 ` Michael Heerdegen
@ 2020-06-13 13:34 ` Jakub Jankiewicz
0 siblings, 0 replies; 15+ messages in thread
From: Jakub Jankiewicz @ 2020-06-13 13:34 UTC (permalink / raw)
To: Michael Heerdegen; +Cc: help-gnu-emacs, Douglas Lewan
[-- Attachment #1: Type: text/plain, Size: 2302 bytes --]
> BTW2, a small problem with your posted version is that it adds one `let'
> binding per branch, but only the outermost is needed:
Thanks I've fixed my macro now it looks like this:
(define-macro (case val . list)
"(case value
((<items>) result1)
((<items>) result2)
[else result3])
Macro for switch case statement. It test if value is any of the item. If
item match the value it will return coresponding result expression value.
If no value match and there is else it will return that result."
(let ((value (gensym)))
`(let ((,value ,val))
,(let iter ((list list))
(if (pair? list)
(let* ((item (car list))
(first (car item))
(result (cadr item))
(rest (cdr list)))
`(if (member ,value ',first)
,result
,(if (and (pair? rest)
(eq? (caar rest) 'else))
(cadar rest)
(if (not (null? rest))
(iter rest))))))))))
It's written in Scheme because that was my original implementation, I used
named let in Emacs you probably will need flet or create helper function
outside of macro. So I guess I will need to use that first implementation
only as example of recursive macro.
There is another example of recursive macros in book [Let Over Lambda][1] in
printed version on page 135. And there is also chapter in [On Lips][2] on page
139 where there is one problem that you may find (probably issue OP had) if
you expand with expansion that have `if` test inside, it will create infinite
loop, expansion need to be conditional so recursive check that stop the loop
need to be called at macro level, it can't be present in expansion.
This is example macro that will not work
(defmacro nthb (n lst)
`(if (= ,n 0)
(car ,lst)
(nthb (- ,n 1) (cdr ,lst))))
here recursive guard is present in expansion and it will not compile becuase
it's infinite loop.
[1]: https://letoverlambda.com/index.cl/guest/chap5.html#sec_5
[2]: http://www.paulgraham.com/onlisptext.html
--
Jakub Jankiewicz, Web Developer
https://jcubic.pl/me
[-- Attachment #2: Podpis cyfrowy OpenPGP --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Compiling a recursive macro
2020-06-11 21:23 ` Douglas Lewan
2020-06-11 21:32 ` Michael Heerdegen
@ 2020-06-11 22:02 ` Stefan Monnier
1 sibling, 0 replies; 15+ messages in thread
From: Stefan Monnier @ 2020-06-11 22:02 UTC (permalink / raw)
To: help-gnu-emacs
> (defmacro mmm ()
> (cond ((at-root-p)
> do tree-wide stuff)
> (t
> (with-current-buffer root (mmm)))
I think you're confused.
It doesn't make much sense to do `with-current-buffer` inside a macro
(well, it can make sense, but only in rather unusual circumstances).
So in the absence of more details, I'll assume that making it a function
is the better option.
Stefan
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Compiling a recursive macro
2020-06-11 20:57 ` Stefan Monnier
2020-06-11 21:23 ` Douglas Lewan
@ 2020-06-11 21:27 ` Michael Heerdegen
1 sibling, 0 replies; 15+ messages in thread
From: Michael Heerdegen @ 2020-06-11 21:27 UTC (permalink / raw)
To: help-gnu-emacs
Stefan Monnier <monnier@iro.umontreal.ca> writes:
> > That suggests to me that you can't compile any recursive macro.
>
> Depends what you mean by "recursive macro".
> What this prevents is to use a macro inside the definition of a macro.
Which means: the macro is not allowed to be used to generate the
expansion. But it may appear in the expansion.
> Most cases of "recursive macros" instead just returns code which
> itself uses that macro.
> [...]
> This works just fine (and may inf-loop, of course).
That's indeed the most common problem in this area I think.
@Douglas: Often it helps me to remember the macro expander as a normal
function.
You can literally rewrite a macro definition
(defmacro my-macro (args...)
body...)
using one function call as macro body instead:
(defmacro my-macro (args...)
(my-macro-expander args...))
with
(defun my-macro-expander (args...)
body...)
where body... is the same as above in the defmacro.
Keeping that in mind, the answer to your question is more obvious, and
practically you can use the above transformation to trace or edebug
`my-macro-expander' to see what happens when the macro is actually
expanded somewhere.
Michael.
^ permalink raw reply [flat|nested] 15+ messages in thread
* Re: Compiling a recursive macro
2020-06-11 20:15 Compiling a recursive macro Douglas Lewan
2020-06-11 20:57 ` Stefan Monnier
@ 2020-06-12 0:03 ` Jakub Jankiewicz
1 sibling, 0 replies; 15+ messages in thread
From: Jakub Jankiewicz @ 2020-06-12 0:03 UTC (permalink / raw)
To: Douglas Lewan; +Cc: help-gnu-emacs
[-- Attachment #1: Type: text/plain, Size: 1761 bytes --]
On Thu, 11 Jun 2020 16:15:05 -0400
Douglas Lewan <d.lewan2000@gmail.com> wrote:
> I'm not an expert on macros whatsoever. I apologize if this is idiotic.
>
> I've been doing battle trying to define a recursive macro, and I'd like
> it to be byte compiled. However, in the info (elisp) Compiling Macros, I
> find the following:
>
> In order for compilation of macro calls to work, the macros must
> already be defined in Lisp when the calls to them are compiled.
>
> That suggests to me that you can't compile any recursive macro. Do I
> understand it correctly? If I do, then I'm curious if there's a common
> style for getting around this.
Here is example of recursive macro:
(defmacro case_ (val &rest list)
"(case value
((<items>) result1)
((<items>) result2)
[else result3])
Macro for switch case statement. It test if value is any of the item. If
item match the value it will return coresponding result expression value.
If no value match and there is else it will return that result."
(if (listp list)
(let* ((item (car list))
(first (car item))
(result (cadr item))
(rest (cdr list))
(value (gensym)))
`(let ((,value ,val))
(if (member ,value ',first)
,result
,(if (and (listp rest)
(eq (caar rest) 'else))
'xxx
(if (not (null rest))
`(case_ ,value ,@rest))))))
nil))
(case_ (+ 1 2)
((1 2) 'foo)
((4 3) 'bar))
it's converted from Scheme code for my LIPS interpteter.
--
Jakub Jankiewicz, Web Developer
https://jcubic.pl/me
[-- Attachment #2: Podpis cyfrowy OpenPGP --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 15+ messages in thread
end of thread, other threads:[~2020-06-13 13:34 UTC | newest]
Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-06-11 20:15 Compiling a recursive macro Douglas Lewan
2020-06-11 20:57 ` Stefan Monnier
2020-06-11 21:23 ` Douglas Lewan
2020-06-11 21:32 ` Michael Heerdegen
2020-06-11 21:38 ` Douglas Lewan
2020-06-11 21:55 ` Michael Heerdegen
2020-06-11 22:21 ` Douglas Lewan
2020-06-12 10:49 ` Michael Heerdegen
2020-06-12 16:11 ` Douglas Lewan
2020-06-12 2:10 ` Douglas Lewan
2020-06-13 9:49 ` Michael Heerdegen
2020-06-13 13:34 ` Jakub Jankiewicz
2020-06-11 22:02 ` Stefan Monnier
2020-06-11 21:27 ` Michael Heerdegen
2020-06-12 0:03 ` Jakub Jankiewicz
Code repositories for project(s) associated with this external index
https://git.savannah.gnu.org/cgit/emacs.git
https://git.savannah.gnu.org/cgit/emacs/org-mode.git
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.