From: Dai Yuwen
Subject: How to use macro parameters in a string
Date: 
Message-ID: <b97hkj$20hu$1@mail.cn99.com>
Dear all,

I wrote a simple macro like this:

(defmacro join-string-list (list delimiter)
   `(format nil "~{~A~^,delimiter~}" ,list))


But the expansion of the above macro is:

(FORMAT NIL "~{~A~^,delimiter~}" L)

Obviously the comma (,) operator doesn't take effect in a string.  How do I write macros in this 
situation?  Thanks in advance.

Best regards,
Dai Yuwen

From: Peter Seibel
Subject: Re: How to use macro parameters in a string
Date: 
Message-ID: <m3y91kd2vz.fsf@javamonkey.com>
Dai Yuwen <·····@micetek.com.cn> writes:

> Dear all,
> 
> I wrote a simple macro like this:
> 
> (defmacro join-string-list (list delimiter)
>    `(format nil "~{~A~^,delimiter~}" ,list))
> 
> 
> But the expansion of the above macro is:
> 
> (FORMAT NIL "~{~A~^,delimiter~}" L)
> 
> Obviously the comma (,) operator doesn't take effect in a string.  How
> do I write macros in this situation?  Thanks in advance.

This will work at least as well as your version would have worked if
the comma interpolation had done what you wanted:

  (defmacro join-string-list (list delimiter)
    (let ((format-string (format nil "~~{~~A~~^~A~~}" delimiter)))
     `(format nil ,format-string ,list)))

However, you'll want to keep in mind that the delimiter argument is
not going to be evaluated so while you can something like this:

  (join-string-list '(1 2 3) #\,)

and probably get what you want ("1,2,3"), because #\, is self
evaluating, you may not get what you're expecting if you write
something like this (or it's equivalent):

  (let ((d #\,)) (join-string-list '(1 2 3) d))

which yields "1D2D3". If you understand why that is, great. Otherwise
you should probably ponder than until you do understand; you'll gain a
useful insight into how macros work. (I'm only guessing that you
*might* not already have that insight based on your confusion about
the comma inside the string. If you get it already, as I said, great.)

If you want the second form (with the LET) to yield the same result,
as the first, you'd have to move the creation of the format-string
into the expaned code. At which point you're not really doing any work
at compile time and thus aren't gaining much of anything by using a
macro. (It's not clear that you're gaining much anyway, by using a
macro, as presumably the main cost of this operation is going to be
*inside* FORMAT. Though I haven't actually profiled it to know for
sure.) In that case a simple function would suffice. This is gross in
its own way but not too horrible.

  (defun join-string-list (list delimiter)
    (format nil (format nil "~~{~~a~~^~a~~}" delimiter) list))


(Some FORMAT wizard will probably show us how to do it in one format
command; I tried but couldn't pull it off.)

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

  The intellectual level needed   for  system design is  in  general
  grossly  underestimated. I am  convinced  more than ever that this
  type of work is very difficult and that every effort to do it with
  other than the best people is doomed to either failure or moderate
  success at enormous expense. --Edsger Dijkstra
From: Christopher C. Stacy
Subject: Re: How to use macro parameters in a string
Date: 
Message-ID: <u4r4838gf.fsf@dtpq.com>
>>>>> On Tue, 06 May 2003 13:36:45 +0800, Dai Yuwen ("Dai") writes:

 Dai> Dear all,
 Dai> I wrote a simple macro like this:

 Dai> (defmacro join-string-list (list delimiter)
 Dai>    `(format nil "~{~A~^,delimiter~}" ,list))

 Dai> But the expansion of the above macro is:

 Dai> (FORMAT NIL "~{~A~^,delimiter~}" L)

 Dai> Obviously the comma (,) operator doesn't take effect in a string.
 Dai> How do I write macros in this situation?  Thanks in advance.


You could have the macro compute the FORMAT control string,
and then use the result in the macroexpansion.

(defmacro join-string-list (list delimiter)
  (let ((control-string (concatenate 'string "~{~A~^" delimiter "~}")))
    `(format nil ,control-string ,list)))
From: Dai Yuwen
Subject: Re: How to use macro parameters in a string
Date: 
Message-ID: <b97n70$24ei$1@mail.cn99.com>
Christopher C. Stacy wrote:
>>>>>>On Tue, 06 May 2003 13:36:45 +0800, Dai Yuwen ("Dai") writes:
> 
> 
>  Dai> Dear all,
>  Dai> I wrote a simple macro like this:
> 
>  Dai> (defmacro join-string-list (list delimiter)
>  Dai>    `(format nil "~{~A~^,delimiter~}" ,list))
> 
>  Dai> But the expansion of the above macro is:
> 
>  Dai> (FORMAT NIL "~{~A~^,delimiter~}" L)
> 
>  Dai> Obviously the comma (,) operator doesn't take effect in a string.
>  Dai> How do I write macros in this situation?  Thanks in advance.
> 
> 
> You could have the macro compute the FORMAT control string,
> and then use the result in the macroexpansion.
> 
> (defmacro join-string-list (list delimiter)
>   (let ((control-string (concatenate 'string "~{~A~^" delimiter "~}")))
>     `(format nil ,control-string ,list)))

Thank you very much!