* Difficult macro question: Doing custom `let'
@ 2003-08-18 17:43 Jari Aalto+mail.emacs
2003-08-18 17:57 ` Barry Margolin
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Jari Aalto+mail.emacs @ 2003-08-18 17:43 UTC (permalink / raw)
I'm trying to make a custom `let' macro. The basic idea is that
the variables defined inside `let' should be user defined and
the `let' form simply should set them to nil. Something like:
(setq list '(a b c))
Something, a macro, that turns that into:
(let (a
b
b)
I've experimented with this:
(nconc
(list 'let)
(list
(mapcar
(function
(lambda (x)
(list x nil)))
list)))
--> (let ((a nil) (b nil) (c nil)))
Now the problem is, How Do I make a macro that does exactly that above?
The macro would be called inside function body:
(defun my-test ()
(my-let-transform list
(message "It worked.")))
Which should be after macroexpand:
(defun my-test ()
(let (a
b
b)
(message "It worked.")))
Now, how do I get there?
Jari
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Difficult macro question: Doing custom `let'
2003-08-18 17:43 Jari Aalto+mail.emacs
@ 2003-08-18 17:57 ` Barry Margolin
2003-08-18 18:00 ` Johan Bockgård
2003-08-18 21:20 ` Pascal Bourguignon
2 siblings, 0 replies; 5+ messages in thread
From: Barry Margolin @ 2003-08-18 17:57 UTC (permalink / raw)
In article <1xviq2u3.fsf@blue.sea.net>,
Jari Aalto+mail.emacs <jari.aalto@poboxes.com> wrote:
>I'm trying to make a custom `let' macro. The basic idea is that
>the variables defined inside `let' should be user defined and
>the `let' form simply should set them to nil. Something like:
>
>(setq list '(a b c))
>
>Something, a macro, that turns that into:
>
> (let (a
> b
> b)
(defmacro my-let (symbols &rest body)
`(progv ,symbols ,(make-list (length symbols) nil)
,@body))
--
Barry Margolin, barry.margolin@level3.com
Level(3), Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Difficult macro question: Doing custom `let'
2003-08-18 17:43 Jari Aalto+mail.emacs
2003-08-18 17:57 ` Barry Margolin
@ 2003-08-18 18:00 ` Johan Bockgård
2003-08-18 21:20 ` Pascal Bourguignon
2 siblings, 0 replies; 5+ messages in thread
From: Johan Bockgård @ 2003-08-18 18:00 UTC (permalink / raw)
jari.aalto@poboxes.com (Jari Aalto+mail.emacs) writes:
> I'm trying to make a custom `let' macro. The basic idea is that the
> variables defined inside `let' should be user defined and the `let'
> form simply should set them to nil. Something like:
,----[ C-h f progv RET ]
| progv is a Lisp macro in `cl-macs'.
| (progv SYMBOLS VALUES &rest BODY)
|
| Bind SYMBOLS to VALUES dynamically in BODY.
| The forms SYMBOLS and VALUES are evaluated, and must evaluate to lists.
| Each SYMBOL in the first list is bound to the corresponding VALUE in the
| second list (or made unbound if VALUES is shorter than SYMBOLS); then the
| BODY forms are executed and their result is returned. This is much like
| a `let' form, except that the list of symbols can be computed at run-time.
`----
--
Johan Bockgård
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Difficult macro question: Doing custom `let'
@ 2003-08-18 18:20 lawrence mitchell
0 siblings, 0 replies; 5+ messages in thread
From: lawrence mitchell @ 2003-08-18 18:20 UTC (permalink / raw)
Jari Aalto+mail.emacs wrote:
[...] given list => '(a b c), get (let (a b c) ...)
> Now the problem is, How Do I make a macro that does exactly that above?
> The macro would be called inside function body:
> (defun my-test ()
> (my-let-transform list
> (message "It worked.")))
> Which should be after macroexpand:
> (defun my-test ()
> (let (a
> b
> b)
> (message "It worked.")))
If you do (require 'cl), you can try something like this:
(defmacro* my-transform-list ((&rest vars) &body body)
;; If VARS is a variable, assume we wanted its value.
;; otherwise, we just take it as a literal list.
;; This means that both (my-transform-list (a b) ...)
;; and (my-transform-list foo ...) work (assuming foo is boundp).
(ignore-errors
(setq vars (symbol-value vars)))
`(let ,vars
,@body))
(macroexpand '(my-transform-list (a b c) (message "It works.")))
=> (let (a b c)
(message "It works."))
but also:
(setf list '(a b c))
(macroexpand '(my-transform-list list (message "It works.")))
=> (let (a b c)
(message "It works."))
Note that there is no need to quote the list of variables if you
give them literally.
--
lawrence mitchell <wence@gmx.li>
^ permalink raw reply [flat|nested] 5+ messages in thread
* Re: Difficult macro question: Doing custom `let'
2003-08-18 17:43 Jari Aalto+mail.emacs
2003-08-18 17:57 ` Barry Margolin
2003-08-18 18:00 ` Johan Bockgård
@ 2003-08-18 21:20 ` Pascal Bourguignon
2 siblings, 0 replies; 5+ messages in thread
From: Pascal Bourguignon @ 2003-08-18 21:20 UTC (permalink / raw)
jari.aalto@poboxes.com (Jari Aalto+mail.emacs) writes:
> I'm trying to make a custom `let' macro. The basic idea is that
> the variables defined inside `let' should be user defined and
> the `let' form simply should set them to nil. Something like:
>
> (setq list '(a b c))
>
> Something, a macro, that turns that into:
>
> (let (a
> b
> b)
Are you aware that this is exactly the behavior of normal let, be it
form emacs lisp or from Common-Lisp?
(let (a b c) (insert (format "==> a=%s b=%s c=%s\n" a b c)))
==> a=nil b=nil c=nil
> I've experimented with this:
>
> (nconc
> (list 'let)
> (list
> (mapcar
> (function
> (lambda (x)
> (list x nil)))
> list)))
> --> (let ((a nil) (b nil) (c nil)))
>
> Now the problem is, How Do I make a macro that does exactly that above?
> The macro would be called inside function body:
> Now, how do I get there?
A macro is merely a function, only that it executes at compile time
instead of at run time. So:
(defmacro my-let (var-list &rest body)
(nconc
(list 'let)
(list
(mapcar
(function
(lambda (x)
(list x nil)))
var-list))
body))
(show (macroexpand '(my-let (a b c) (statement1) (statement2))))
==> (let ((a nil) (b nil) (c nil)) (statement1) (statement2))
Now, when you write macros (and sometimes in plain functions), you may
use with great benefit backquote/coma constructs. The backquote
introduce a "literal" construct, like the quote, only that inside it,
anything introduced by a coma is evaluated, and ,@ introduce the
elements of an evaluated list.
This allow you to write a result as a template with some values:
(defmacro my-let (var-list &rest body)
`(let ,(mapcar (lambda (x) (list x nil)) var-list)
,@body))
(show (macroexpand '(my-let (a b c) (statement1) (statement2))))
==> (let ((a nil) (b nil) (c nil)) (statement1) (statement2))
Note that it's (mapcar (lambda (x) (list x nil)) var-list) and the
symbol body that are evaluated. The mapcar returns a list that is
inserted as is, and the evaluation of body returns the list
((statement1) (statemet2)) of which the elements are inserted.
--
__Pascal_Bourguignon__ http://www.informatimago.com/
----------------------------------------------------------------------
Do not adjust your mind, there is a fault in reality.
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2003-08-18 21:20 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-08-18 18:20 Difficult macro question: Doing custom `let' lawrence mitchell
-- strict thread matches above, loose matches on Subject: below --
2003-08-18 17:43 Jari Aalto+mail.emacs
2003-08-18 17:57 ` Barry Margolin
2003-08-18 18:00 ` Johan Bockgård
2003-08-18 21:20 ` Pascal Bourguignon
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).