all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* 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

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.