From: Rene de Visser
Subject: Macros: returning multiple lists
Date: 
Message-ID: <d001h0$jvc$05$1@news.t-online.com>
Hello,

I want to do something like this:

(defmacro repeat-with-colors (&rest rest)
  (mapcan
   (lambda (form)
         (map 'list
              (lambda (color)
                (print
                 (read-from-string
                  (substitute-subseq (print (format nil "~S" form))
                                     "%COLOR%" (symbol-name color)))))
              (color-list)))
       rest))

but that returns multiple forms rather than a list of multiple forms, so 
that
I can do things like
(+
                (repeat-with-colors
                 (length (board-%color%-stones-pos board))))

producing

(+ form1 form2 form3 ...)

Or in defclass, defstruct, etc.

The trouble is that macros return just one list.

How do get around this?

I thought about something like

(with-colors
   (+
                (repeat-colors
                 (length (board-%color%-stones-pos board)))))

using macrolet, but this just shifts the problem to macrolet.

I am pretty sure I found a way around this problem sometime in the past, but 
I can't  remember how.

Rene.

From: Barry Margolin
Subject: Re: Macros: returning multiple lists
Date: 
Message-ID: <barmar-912EF0.16513728022005@comcast.dca.giganews.com>
In article <···············@news.t-online.com>,
 "Rene de Visser" <··············@hotmail.com> wrote:

> Hello,
> 
> I want to do something like this:
> 
> (defmacro repeat-with-colors (&rest rest)
>   (mapcan
>    (lambda (form)
>          (map 'list
>               (lambda (color)
>                 (print
>                  (read-from-string
>                   (substitute-subseq (print (format nil "~S" form))
>                                      "%COLOR%" (symbol-name color)))))
>               (color-list)))
>        rest))
> 
> but that returns multiple forms rather than a list of multiple forms, so 
> that
> I can do things like
> (+
>                 (repeat-with-colors
>                  (length (board-%color%-stones-pos board))))
> 
> producing
> 
> (+ form1 form2 form3 ...)
> 
> Or in defclass, defstruct, etc.
> 
> The trouble is that macros return just one list.
> 
> How do get around this?

Have the macro return (LIST form1 form2 form3 ...) and then use it as:

(apply #'+ (repeat-with-colors ...))

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
From: Pascal Bourguignon
Subject: Re: Macros: returning multiple lists
Date: 
Message-ID: <87psyknxvb.fsf@thalassa.informatimago.com>
"Rene de Visser" <··············@hotmail.com> writes:

> Hello,
> 
> I want to do something like this:
> 
> (defmacro repeat-with-colors (&rest rest)
>   (mapcan
>    (lambda (form)
>          (map 'list
>               (lambda (color)
>                 (print
>                  (read-from-string
>                   (substitute-subseq (print (format nil "~S" form))
>                                      "%COLOR%" (symbol-name color)))))
>               (color-list)))
>        rest))
> 
> but that returns multiple forms rather than a list of multiple forms, so 
> that
> I can do things like
> (+
>                 (repeat-with-colors
>                  (length (board-%color%-stones-pos board))))
> producing
> 
> (+ form1 form2 form3 ...)

Why do you want to use a macro then?  You can generate forms with a
function too:

(defun generate-forms-with-colors (&rest rest)
    ...)

But do you really want to generate forms?  Why not compute the values?

    (defun values-with-colors (&rest rest) 
        ...) 

returning a list of values, then you can merely use:

    (reduce (function +) 
            (values-with-colors (length (board-%color%-stones-pos board))))


If you insist to return forms, it might be because you want to use
these forms in macros. For example:

    (defmacro sum-colors (&rest rest)
        (let ((forms (apply (function generate-forms-with-colors) rest)))
           (if (< (length forms) call-arguments-limit)
              `(+ ,@forms)
              `(reduce (function +) ',@forms))))

    (sum-colors (length (board-%color%-stones-pos board)))


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Grace personified,
I leap into the window.
I meant to do that.
From: Rene de Visser
Subject: Re: Macros: returning multiple lists
Date: 
Message-ID: <d02irn$t5e$00$1@news.t-online.com>
"Pascal Bourguignon" <····@mouse-potato.com> schrieb im Newsbeitrag >> I can 
do things like
>> (+
>>                 (repeat-with-colors
>>                  (length (board-%color%-stones-pos board))))
>> producing
>>
>> (+ form1 form2 form3 ...)
>
> If you insist to return forms, it might be because you want to use
> these forms in macros.
Exactly. Including macros not written by me, such as defclass, defun, etc.
In the end, I went with.

(defun with-symbol-repeat (repeat-marker replace-symbol substitution-list 
body)
  (let ((replace-string (symbol-name replace-symbol)))
    (labels ((repeat-forms (repeat-forms)
               (mapcan
                (lambda (form)
                  (map 'list
                       (lambda (symbol-component)
                         (read-from-string
                          (substitute-subseq
                           (format nil "~S" form)
                           replace-string (symbol-name symbol-component))))
                       substitution-list))
                repeat-forms))
             (walk-body (list)
               (let ((new-list))
                 (dolist (form list)
                   (if (consp form)
                       (if  (eql (first form) repeat-marker)
                           (dolist (form (repeat-forms (rest form)))
                             (push (walk-body form) new-list))
                         (push (walk-body form) new-list))
                     (push form new-list)))
                 (nreverse new-list))))
      (walk-body body))))

(defmacro with-colors (form)
  (with-symbol-repeat '!* '%color% (color-list) form))

Not perfect, but should cover most cases without too many problems.
This allows things such as:

(with-colors
 (defclass test ()
   ((normal-attribute)
    (!* (%color%-list :accessor board-%color%-stones-pos))
    (another-attribute))))

(macroexpand '(with-colors
               (+ (!* (length (board-%color%-stones-pos board))))))
giving

(+ (LENGTH (BOARD-WHITE-STONES-POS BOARD)) (LENGTH (BOARD-GREY-STONES-POS 
BOARD)) (LENGTH (BOARD-BLACK-STONES-POS BOARD)))

Rene.
From: Thomas A. Russ
Subject: Re: Macros: returning multiple lists
Date: 
Message-ID: <ymi4qfv1cmo.fsf@sevak.isi.edu>
The standard mechanism to have multiple forms returned from macros is to
enclose them in a PROGN.  That assumes, of course, that you want the
forms to execute for side effects rather than value.  If you want value,
then you pretty much have to make a list of them and apply any other
external-to-the-macro operations to that list.

-- 
Thomas A. Russ,  USC/Information Sciences Institute