help-gnu-emacs
[Top][All Lists]
Advanced

[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


reply via email to

[Prev in Thread] Current Thread [Next in Thread]