* problem with macro definitions
@ 2017-04-27 22:44 hector
2017-04-29 9:39 ` Michael Heerdegen
0 siblings, 1 reply; 6+ messages in thread
From: hector @ 2017-04-27 22:44 UTC (permalink / raw)
To: help-gnu-emacs
Hi.
I'm trying to write a macro. Honestly I find this is one of the most
difficult matters about learning ELISP.
I was looking for the complementary of nth, that is, a function that
returns the index of an element. Since it can be done at compilation
time I thought it was a good candidate for a macro:
(defmacro idx (list telt)
`(let (found
(idx 0))
(dolist (elt ,list found)
(when (eq elt ,telt)
(setq found idx))
(setq idx (1+ idx)))))
Then I wrote another one:
(defconst start-states '(initial red blue yellow))
(defconst shift-val 10)
(defmacro state-eof (st)
(let ((val (+ shift-val (idx start-states st))))
val))
Probably there is a better way to accomplish this. Anyway I'd like to know
why it doesn't work.
This yields 2 as expected:
(idx start-states 'blue)
so I expected this to return 12:
(state-eof 'blue)
but instead I get:
wrong-type-argument number-or-marker-p nil
What am I doing wrong?
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: problem with macro definitions
2017-04-27 22:44 problem with macro definitions hector
@ 2017-04-29 9:39 ` Michael Heerdegen
2017-04-29 9:52 ` Michael Heerdegen
2017-04-29 16:06 ` hector
0 siblings, 2 replies; 6+ messages in thread
From: Michael Heerdegen @ 2017-04-29 9:39 UTC (permalink / raw)
To: help-gnu-emacs
hector <hectorlahoz@gmail.com> writes:
> I was looking for the complementary of nth, that is, a function that
> returns the index of an element. Since it can be done at compilation
> time
Not if you want to use it on values that are known only at run-time.
> I thought it was a good candidate for a macro:
No, not really:
> (defmacro idx (list telt)
> `(let (found
> (idx 0))
> (dolist (elt ,list found)
> (when (eq elt ,telt)
> (setq found idx))
> (setq idx (1+ idx)))))
You loose nothing when you rewrite this as a function. In this
implementation, the index is calculated at run-time.
> Then I wrote another one:
>
> (defconst start-states '(initial red blue yellow))
> (defconst shift-val 10)
>
> (defmacro state-eof (st)
> (let ((val (+ shift-val (idx start-states st))))
> val))
That comes closer to what you intend to implement.
> Probably there is a better way to accomplish this. Anyway I'd like to
> know why it doesn't work.
>
> This yields 2 as expected:
> (idx start-states 'blue)
>
> so I expected this to return 12:
> (state-eof 'blue)
Note that macros don't evaluate their arguments. The argument 'blue you
pass, a read syntax for (quote blue), is a list of two elements. This
doesn't appear as an element of `start-states' which consists of four
symbols.
Your macro `state-eof' actually does find the value at compile time.
It's still an unusual use case for `defmacro' which is normally code
transformation. Your `state-eof' calls just expand to a number. You
can do this, but in real life one would probably prefer a different
solution, like defining this number as a `defconst', depending on the
actual use case.
Regards,
Michael.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: problem with macro definitions
2017-04-29 9:39 ` Michael Heerdegen
@ 2017-04-29 9:52 ` Michael Heerdegen
2017-04-29 16:06 ` hector
1 sibling, 0 replies; 6+ messages in thread
From: Michael Heerdegen @ 2017-04-29 9:52 UTC (permalink / raw)
To: help-gnu-emacs
Michael Heerdegen <michael_heerdegen@web.de> writes:
> Your macro `state-eof' actually does find the value at compile time.
> It's still an unusual use case for `defmacro' which is normally code
> transformation. Your `state-eof' calls just expand to a number. You
> can do this, but in real life one would probably prefer a different
> solution, like defining this number as a `defconst', depending on the
> actual use case.
BTW, a good method to do calculations at compile time is to use
`eval-when-compile'. Depending on the actual use case, it's mostly
still good enough and easier to do such things (once) at load time.
Michael.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: problem with macro definitions
2017-04-29 9:39 ` Michael Heerdegen
2017-04-29 9:52 ` Michael Heerdegen
@ 2017-04-29 16:06 ` hector
2017-05-09 8:14 ` hector
1 sibling, 1 reply; 6+ messages in thread
From: hector @ 2017-04-29 16:06 UTC (permalink / raw)
To: help-gnu-emacs
Thank you for your reply.
On Sat, Apr 29, 2017 at 11:39:13AM +0200, Michael Heerdegen wrote:
> hector <hectorlahoz@gmail.com> writes:
>
> > I was looking for the complementary of nth, that is, a function that
> > returns the index of an element. Since it can be done at compilation
> > time
>
> Not if you want to use it on values that are known only at run-time.
I know. In this case when the list is constant it seemed to be right.
> > I thought it was a good candidate for a macro:
>
> No, not really:
>
> > (defmacro idx (list telt)
> > `(let (found
> > (idx 0))
> > (dolist (elt ,list found)
> > (when (eq elt ,telt)
> > (setq found idx))
> > (setq idx (1+ idx)))))
>
> You loose nothing when you rewrite this as a function. In this
> implementation, the index is calculated at run-time.
Let me rephrase your statement:
"You gain nothing when you write this as a macro. In this
implementation, the index is calculated at run-time"
I'm aware of that now. This is not what I meant.
I'll try to rewrite it.
> Note that macros don't evaluate their arguments. The argument 'blue you
> pass, a read syntax for (quote blue), is a list of two elements. This
> doesn't appear as an element of `start-states' which consists of four
> symbols.
This is the key to my confusion.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: problem with macro definitions
2017-04-29 16:06 ` hector
@ 2017-05-09 8:14 ` hector
2017-05-09 14:16 ` Michael Heerdegen
0 siblings, 1 reply; 6+ messages in thread
From: hector @ 2017-05-09 8:14 UTC (permalink / raw)
To: help-gnu-emacs
On Sat, Apr 29, 2017 at 06:06:32PM +0200, hector wrote:
> Thank you for your reply.
>
> On Sat, Apr 29, 2017 at 11:39:13AM +0200, Michael Heerdegen wrote:
> > hector <hectorlahoz@gmail.com> writes:
> >
> > > I was looking for the complementary of nth, that is, a function that
> > > returns the index of an element. Since it can be done at compilation
> > > time
> >
> > Not if you want to use it on values that are known only at run-time.
>
> I know. In this case when the list is constant it seemed to be right.
>
> > > I thought it was a good candidate for a macro:
> >
> > No, not really:
> >
> > > (defmacro idx (list telt)
> > > `(let (found
> > > (idx 0))
> > > (dolist (elt ,list found)
> > > (when (eq elt ,telt)
> > > (setq found idx))
> > > (setq idx (1+ idx)))))
> >
> > You loose nothing when you rewrite this as a function. In this
> > implementation, the index is calculated at run-time.
>
> Let me rephrase your statement:
>
> "You gain nothing when you write this as a macro. In this
> implementation, the index is calculated at run-time"
>
> I'm aware of that now. This is not what I meant.
> I'll try to rewrite it.
I did it. This is what I meant:
(defmacro idx (list needle)
(let (found
(haystack (eval list))
(idx 0))
(while (not found)
(when (eq (car haystack) needle)
(setq found idx))
(setq idx (1+ idx))
(setq haystack (cdr haystack)))
found))
The macro expansion is just a number.
I come from C. I know each language has its idioms.
I don't know if this is good LISP. But I was just trying
to get the equivalent of a C enum. In most cases it can
be achieved with symbols but in this case I needed the
integer. With the improvement that I don't traverse the
whole list, just until the element (needle) is found.
I'm not quite sure what the "(let ((haystack (eval list))))"
does but it works.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: problem with macro definitions
2017-05-09 8:14 ` hector
@ 2017-05-09 14:16 ` Michael Heerdegen
0 siblings, 0 replies; 6+ messages in thread
From: Michael Heerdegen @ 2017-05-09 14:16 UTC (permalink / raw)
To: help-gnu-emacs
hector <hectorlahoz@gmail.com> writes:
> I did it. This is what I meant:
>
> (defmacro idx (list needle)
> (let (found
> (haystack (eval list))
> (idx 0))
> (while (not found)
> (when (eq (car haystack) needle)
> (setq found idx))
> (setq idx (1+ idx))
> (setq haystack (cdr haystack)))
> found))
>
> The macro expansion is just a number.
Yes, that's true now.
> I'm not quite sure what the "(let ((haystack (eval list))))" does but
> it works.
A macro doesn't evaluate its arguments. Normally, arguments are
evaluated when the expanded code (with argument expressions "pasted in")
is run. You want to do the whole calculation at compile time, and you
want to allow LIST to be an expression (known at compile time), so you
need to evaluate it explicitly to get a list value.
The same applies to the NEEDLE argument btw.
Michael.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2017-05-09 14:16 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2017-04-27 22:44 problem with macro definitions hector
2017-04-29 9:39 ` Michael Heerdegen
2017-04-29 9:52 ` Michael Heerdegen
2017-04-29 16:06 ` hector
2017-05-09 8:14 ` hector
2017-05-09 14:16 ` Michael Heerdegen
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).