[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Evaluation of macro arguments
From: |
duthen . mac . 01 |
Subject: |
Re: Evaluation of macro arguments |
Date: |
Fri, 8 Jan 2016 15:13:38 -0800 (PST) |
User-agent: |
G2/1.0 |
Hello!
Le mardi 5 janvier 2016 21:30:52 UTC+1, Marcin Borkowski a écrit :
> On 2016-01-05, at 20:39, Marcin Borkowski wrote:
>
> > On 2016-01-05, at 20:22, Pascal J. Bourguignon wrote:
> >>
> >> (let ((i 0))
> >> (list (range i 'upto (incf i 10)) ; bam!
> >> i))
> >>
> >> I hope you may debug it well.
> OK, technically you win, since I didn't notice that I evaluated `to'
> multiple times. Still, this was not what I was asking about - though
> thank you for pointing that out to me. It would be rather embarassing
> if I missed it.
If you plan to use a variable "dir" with a "dynamic" value like this,
(range a (if some-test 'upto 'downto) b)
you have to "evaluate" "dir" at run time.
But if you want to restrict it to a "lexical" symbol, you can do something like
this:
(defmacro range (from dir to)
(declare (debug (form symbolp form)) (indent 3))
(let ((delta
(cond
((eq dir 'upto) 1)
((eq dir 'downto) -1)
(t (error "wrong dir: %s" dir)))))
`(let ((i ,from)
(to ,to)
(list (list)))
(while (not (= i to))
(push i list)
(setq i (+ i ,delta)))
(nreverse list))))
(defun test ()
(let ((i 0))
(list (range i upto (incf i 10))
i)))
(test) -> ((0 1 2 3 4 5 6 7 8 9) 10)
Note that "dir" is checked at expansion time and may generate an error.
I have just a couple of remarks concerning macros:
* if some variable is to be used more than once inside the body macro, it
should be better to link it to a local variable (like "to" and "from" here), as
already seen.
* if the body of the macro does not embed any user code, you don't need to be
afraid of variable conflict. You don't need to generate local variables.
* you must respect the order of argument "evaluation".
For example, this couple of macros seem ok, but...
(defmacro range-up (from to)
(declare (debug (form form)) (indent 2))
`(let ((i ,from)
(to ,to)
(list (list)))
(while (not (> i to))
(push i list)
(incf i))
(nreverse list)))
(defmacro range-down (from to)
(declare (debug (form form)) (indent 2))
`(nreverse (range-up ,to ,from)))
ELISP> (range-up 3 7)
(3 4 5 6 7)
ELISP> (range-down 7 3)
(7 6 5 4 3)
ELISP> (let ((i 7)) (range-down i (decf i 4)))
(3)
HTH
jack
Re: Evaluation of macro arguments, Pascal J. Bourguignon, 2016/01/05