unofficial mirror of help-gnu-emacs@gnu.org
 help / color / mirror / Atom feed
* 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).