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.
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 ***
"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.
"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.
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