From: "Stuart D. Herring" <herring@lanl.gov>
Subject: RFC: `macro-eval'
Date: Wed, 30 Aug 2006 10:11:43 -0700 (PDT) [thread overview]
Message-ID: <43976.128.165.123.18.1156957903.squirrel@webmail.lanl.gov> (raw)
I wrote a macro to automatically generate the boilerplate "delayed
evaluation with uninterned symbol" code needed in many macros (and
described at (elisp)Surprising Local Vars), which I present for comment.
As far as my testing shows, it works both in interpreted and compiled
environments, with the one caveat that, as it uses `progv', it both
requires the cl library at runtime and generates spurious warnings upon
compilation because the byte compiler doesn't recognize that `progv' binds
variables. (This of course is not easily fixed, since `progv' can
calculate the lists of variables to bind at runtime!)
(put 'macro-eval 'lisp-indent-function 1)
(defmacro macro-eval (spec &rest body)
"Eval BODY with symbols in SPEC bound to temporary symbols.
For use in macros. Each element of SPEC looks like VAR or (VAR VAL). At
reevaluation time, each symbol will be bound to the evaluated form of the
corresponding VAL, or to the evaluated form of VAR's value if no VAL.
Note that evaluation and binding occurs like `let' and not `let*'."
(let* ((vars (mapcar (lambda (e) (or (car-safe e) e)) spec))
(vals (mapcar (lambda (e) (if (consp e) `',(cadr e) e)) spec))
(syms (mapcar 'gensym (mapcar 'symbol-name vars)))
(comma '\,))
(list '\` `(progv ',syms
(mapcar 'eval ',(list comma `(mapcar 'eval ',vals)))
,(list comma `(progv ',vars ',syms ,@body))))))
With this, it becomes possible to write the example `for' macro thusly:
(defmacro inc (var) `(setq ,var (1+ ,var)))
(defmacro for (var from init to final do &rest body)
"Execute a simple for loop: (for i from 1 to 10 do (print i))."
;; We evaluate init this way to provide the correct evaluation order.
(macro-eval (init final)
`(let ((,var ,init))
(while (<= ,var ,final)
,@body
(inc ,var)))))
The savings in code are more pronounced when the macro does not bind
client variables, as often the `let's can be discarded entirely.
I'm quite willing to believe there are better ways of achieving this;
improvements and suggestions are welcome. (For instance, is it possible
to do without the `comma' variable?) If it seems useful, I can also
implement a `progv'-like macro that requires static variable selection so
the compiler might be happier. (Of course, let me know if that already
exists!)
Davis
--
This product is sold by volume, not by mass. If it appears too dense or
too sparse, it is because mass-energy conversion has occurred during
shipping.
next reply other threads:[~2006-08-30 17:11 UTC|newest]
Thread overview: 4+ messages / expand[flat|nested] mbox.gz Atom feed top
2006-08-30 17:11 Stuart D. Herring [this message]
2006-08-31 7:33 ` RFC: `macro-eval' Richard Stallman
2006-08-31 7:47 ` David Kastrup
2006-08-31 22:57 ` Richard Stallman
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=43976.128.165.123.18.1156957903.squirrel@webmail.lanl.gov \
--to=herring@lanl.gov \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.