From: Karol Skocik
Subject: macro question
Date: 
Message-ID: <1128096396.843868.88400@o13g2000cwo.googlegroups.com>
Hello,
  I need help with macro style. I sometimes need a macro which outputs
some code, but depending on some variable, I need to add something to
the output or nothing, to be more specific :

I want in a macro to have in let section something like :

`(let ((added-nodes (make-hash-table)))
    ....

or, sometimes I need this :
`(let ((added-nodes (make-hash-table))
       (undo-funcs '()))
    ...

until now, I have found out that I can only make it happen when I make
the decision before defining `(let ..) and then I need to duplicate
code like this :

(if make-undo
    `(let ((added-nodes (make-hash-table))
           (undo-funcs '())) ...
    `(let ((added-nodes (make-hash-table))) ...

and that is ugly. or maybe make a list like 'result-form' and append
stuff to that?
I just can't use ,(when make-undo `(undo-funcs '())) because it leaves
nil in the list when the condition is not true.

How do you usually solve situations like this?
Or did I miss something in basic macro writing rules?

Thank you,
  Karol

From: ··············@hotmail.com
Subject: Re: macro question
Date: 
Message-ID: <1128099937.238733.299950@g44g2000cwa.googlegroups.com>
Karol Skocik wrote:
> Hello,
>   I need help with macro style. I sometimes need a macro which outputs
> some code, but depending on some variable, I need to add something to
> the output or nothing, to be more specific :
>
> I want in a macro to have in let section something like :
>
> `(let ((added-nodes (make-hash-table)))
>     ....
>
> or, sometimes I need this :
> `(let ((added-nodes (make-hash-table))
>        (undo-funcs '()))

Others have given you some specific answers. I have a general
suggestion.

Don't be afraid to create helper-functions in your macro functions.

I.e., if you have a tricky bit of list construction, put it in a
function like

(defmacro ...
  (lables ((make-let-arg () (append ... (if make-undo ... ))))
    `(let ,(make-let-arg) ...))
;; not debugged, but you hopefully get the idea.

where you can work on a separate definition of make-let-arg at the Lisp
prompt until you have all the bells and whistles working.

When working this way, be careful to have everything you need defined
at macro expansion time. Beware that your REPL experiments might not
work when loaded into a fresh Lisp image.
From: Peter Seibel
Subject: Re: macro question
Date: 
Message-ID: <m23bnm4i2h.fsf@gigamonkeys.com>
"Karol Skocik" <············@gmail.com> writes:

> Hello, I need help with macro style. I sometimes need a macro which
> outputs some code, but depending on some variable, I need to add
> something to the output or nothing, to be more specific :
>
> I want in a macro to have in let section something like :
>
> `(let ((added-nodes (make-hash-table)))
>     ....
>
> or, sometimes I need this :
> `(let ((added-nodes (make-hash-table))
>        (undo-funcs '()))
>     ...
>
> until now, I have found out that I can only make it happen when I make
> the decision before defining `(let ..) and then I need to duplicate
> code like this :
>
> (if make-undo
>     `(let ((added-nodes (make-hash-table))
>            (undo-funcs '())) ...
>     `(let ((added-nodes (make-hash-table))) ...
>
> and that is ugly. or maybe make a list like 'result-form' and append
> stuff to that?
> I just can't use ,(when make-undo `(undo-funcs '())) because it leaves
> nil in the list when the condition is not true.
>
> How do you usually solve situations like this?
> Or did I miss something in basic macro writing rules?

You can do this:

  `(let ((added-nodes (make-hash-table))
         ,@(when make-undo `((undo-funcs '()))))
     ...)

Note the extra ()'s around the undo-funcs--they'll get taken of by the
splicing of ,@ which will also strip the NIL if make-undo is false.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Karol Skocik
Subject: Re: macro question
Date: 
Message-ID: <1128099262.681399.35960@o13g2000cwo.googlegroups.com>
thank you.
maybe I should read more about macros before I start playing with them
:)
From: Alan Crowe
Subject: Re: macro question
Date: 
Message-ID: <867jcymqnt.fsf@cawtech.freeserve.co.uk>
Karol Skocik asked:

     I want in a macro to have in let section something like :

     `(let ((added-nodes (make-hash-table)))
	 ....

     or, sometimes I need this :
     `(let ((added-nodes (make-hash-table))
	    (undo-funcs '()))
	 ...

     I just can't use ,(when make-undo `(undo-funcs '()))
     because it leaves nil in the list when the condition is
     not true.

* (defmacro example(make-undo)
    `(let ((added-nodes (make-hash-table))
	   ,@(if make-undo
		 (list `(undo-funcs '()))
	       '()))
       body-forms))

* (macroexpand-1 '(example nil))

(LET ((ADDED-NODES (MAKE-HASH-TABLE)))
  BODY-FORMS)
T
* (macroexpand-1 '(example t))

(LET ((ADDED-NODES (MAKE-HASH-TABLE)) (UNDO-FUNCS 'NIL))
  BODY-FORMS)
T

There is a standard Lisp idiom for implementing filters
using mapcan - wrap what you want in a list, discard by
returning nil. For example select even numbers

* (mapcan (lambda(n)(when (evenp n) (list n)))
	  '(1 2 3 4 5))
=> (2 4)

Using ,@ instead of , permits the use of this idiom.

Alan Crowe
Edinburgh
Scotland
From: Pascal Bourguignon
Subject: Re: macro question
Date: 
Message-ID: <87y85ewlrn.fsf@thalassa.informatimago.com>
"Karol Skocik" <············@gmail.com> writes:
> I just can't use ,(when make-undo `(undo-funcs '())) because it leaves
> nil in the list when the condition is not true.

  ,@(when make-undo `((undo-funcs '())))

> How do you usually solve situations like this?
> Or did I miss something in basic macro writing rules?

This has nothing to do with macros, all with building lists. You don't
need to use backquote/comma to build lists (but it's convenient at
times). You could write:

(let ((make-undo (oddp (random 2))))
  (print (list 'let (append (list (list 'x 1))
                            (when make-undo
                               (list (list 'undo-funcs '())))))))

or:

(let ((make-undo (oddp (random 2))))
  (print `(let ((x 1)
               ,@(when make-undo
                   `((undo-funcs '())))))))


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

Nobody can fix the economy.  Nobody can be trusted with their finger
on the button.  Nobody's perfect.  VOTE FOR NOBODY.