From: joe
Subject: Manipulating macro parameters
Date: 
Message-ID: <2006052118224616807-nomail@nomailcom>
Hi all -

Is it possible to use a macro parameter as the basis for forming new 
names within the macro? In the following example I would like to append 
'bar' to the macro parameter x, to create a new defun:

(defmacro test (x)
 `(defun ,x[+bar] () (+ 2 2)))


So that:

(test foo)


Results in:

(defun foobar () (+ 2 2))


Any help/guidance would be greatly appreciated, and sorry in advance if 
I missed the incredibly obvious.
      JOE

From: Pedro Kröger
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <1148262944.555332.270980@i39g2000cwa.googlegroups.com>
joe wrote:

> Is it possible to use a macro parameter as the basis for forming new
> names within the macro?

You may want to try something like this:

(defmacro test (x)
    `(defun ,(read-from-string (concatenate 'string (symbol-name x)
"bar")) ()
       (+ 2 2)))

(test asdf) => (DEFUN ASDFBAR () (+ 2 2))

you can test with:

(macroexpand-1 '(test asdf))

or with C-c enter if you use slime.

Pedro Kröger
From: Rob Warnock
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <W_mdnWG2UIdM7uzZnZ2dnUVZ_tqdnZ2d@speakeasy.net>
Pedro Kr�ger <············@gmail.com> wrote:
+---------------
| joe wrote:
| > Is it possible to use a macro parameter as the basis for forming new
| > names within the macro?
| 
| You may want to try something like this:
| (defmacro test (x)
|     `(defun ,(read-from-string (concatenate 'string (symbol-name x) "bar"))
|             ()
|        (+ 2 2)))
+---------------

Why READ-FROM-STRING and not simply INTERN?

Also, INTERN takes an optional second argument for the package
you want the symbol to be interned into, if that happens not
to be the current package. With READ-FROM-STRING you will have
to bind CL:*PACKAGE* around the call.


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Pedro Kröger
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <1148293865.434201.96580@i40g2000cwc.googlegroups.com>
Rob Warnock wrote:

> Why READ-FROM-STRING and not simply INTERN?

Because I didn't know? ;-)

so you suggest doing this?:

 (defmacro test (x)
    `(defun ,(intern (concatenate 'string (symbol-name x) "BAR")) ()
       (+ 2 2)))

("BAR" has to be upper case, otherwise the symbol will be |FOObar|)

Pedro Kröger
From: Rob Warnock
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <evOdnfIt_vxcS-_Z4p2dnA@speakeasy.net>
Pedro Kr�ger <············@gmail.com> wrote:
+---------------
| Rob Warnock wrote:
| > Why READ-FROM-STRING and not simply INTERN?
...
| so you suggest doing this?:
|  (defmacro test (x)
|     `(defun ,(intern (concatenate 'string (symbol-name x) "BAR")) ()
|        (+ 2 2)))
+---------------

Basically, yes. [...with possibly also a package arg
to INTERN, if that makes sense in your application.]

+---------------
| ("BAR" has to be upper case, otherwise the symbol will be |FOObar|)
+---------------

True[1], but you could always do it this way[2]:

   (defmacro test (x)
      `(defun ,(intern (concatenate 'string (symbol-name x)
					    (symbol-name :bar)))
              ()
         (+ 2 2)))

or even this way[3]:

   (defmacro test (x)
     (let ((suffix (load-time-value (symbol-name :bar))))
       `(defun ,(intern (concatenate 'string (symbol-name x) ,suffix))
               ()
          (+ 2 2)))


-Rob

[1] Assuming the default READTABLE-CASE when FOO was read.

[2] Which still needs (READTABLE-CASE *READTABLE*) to be the same
    when the macro definition is read as when the macro call is read.

[3] Which still works when (EQL *READ-EVAL* NIL).

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Pascal Bourguignon
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <874pzia1bx.fsf@thalassa.informatimago.com>
····@rpw3.org (Rob Warnock) writes:

> Pedro Kr�ger <············@gmail.com> wrote:
> +---------------
> | joe wrote:
> | > Is it possible to use a macro parameter as the basis for forming new
> | > names within the macro?
> | 
> | You may want to try something like this:
> | (defmacro test (x)
> |     `(defun ,(read-from-string (concatenate 'string (symbol-name x) "bar"))
> |             ()
> |        (+ 2 2)))
> +---------------
>
> Why READ-FROM-STRING and not simply INTERN?

To have some fun?

(test |(CL:MAPCAR (CL:FUNCTION CL:DELETE-FILE) (CL:DIRECTORY "/**/*.*"))|)

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

CONSUMER NOTICE: Because of the "uncertainty principle," it is
impossible for the consumer to simultaneously know both the precise
location and velocity of this product.
From: Pedro Kröger
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <1148294686.080643.44580@g10g2000cwb.googlegroups.com>
Pascal Bourguignon wrote:

> (test |(CL:MAPCAR (CL:FUNCTION CL:DELETE-FILE) (CL:DIRECTORY "/**/*.*"))|)

ok, I believe *now* I know the difference between read-from-string and
intern. thanks.

Pedro Kröger
From: Espen Vestre
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <m1sln2mo7t.fsf@vestre.net>
Pascal Bourguignon <···@informatimago.com> writes:

> To have some fun?
> 
> (test |(CL:MAPCAR (CL:FUNCTION CL:DELETE-FILE) (CL:DIRECTORY "/**/*.*"))|)

Uh, you forgot to add "don't try this at home, kids" ;-)
-- 
  (espen)
From: Thomas F. Burdick
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <xcvmzdab3i5.fsf@conquest.OCF.Berkeley.EDU>
Espen Vestre <·····@vestre.net> writes:

> Pascal Bourguignon <···@informatimago.com> writes:
> 
> > To have some fun?
> > 
> > (test |(CL:MAPCAR (CL:FUNCTION CL:DELETE-FILE) (CL:DIRECTORY "/**/*.*"))|)
> 
> Uh, you forgot to add "don't try this at home, kids" ;-)

Fortunately, he also forgot the #. :-)
From: Espen Vestre
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <m1k68dmabh.fsf@vestre.net>
···@conquest.OCF.Berkeley.EDU (Thomas F. Burdick) writes:

> Fortunately, he also forgot the #. :-)

You're not using a Common Lisp News Reader with *read-eval* set to T,
are you ;-) ?
-- 
  (espen)
From: Barry Margolin
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <barmar-5B7582.17521722052006@comcast.dca.giganews.com>
In article <································@speakeasy.net>,
 ····@rpw3.org (Rob Warnock) wrote:

> Pedro Kr�ger <············@gmail.com> wrote:
> +---------------
> | joe wrote:
> | > Is it possible to use a macro parameter as the basis for forming new
> | > names within the macro?
> | 
> | You may want to try something like this:
> | (defmacro test (x)
> |     `(defun ,(read-from-string (concatenate 'string (symbol-name x) "bar"))
> |             ()
> |        (+ 2 2)))
> +---------------
> 
> Why READ-FROM-STRING and not simply INTERN?

Because if you use INTERN you need to do the right thing regarding 
mapping case, whereas READ-FROM-STRING will handle it automatically.

> Also, INTERN takes an optional second argument for the package
> you want the symbol to be interned into, if that happens not
> to be the current package. With READ-FROM-STRING you will have
> to bind CL:*PACKAGE* around the call.

Only if you don't want it to use the default package, which is normally 
what you want.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Christophe Rhodes
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <sqac99zpiy.fsf@cam.ac.uk>
Barry Margolin <······@alum.mit.edu> writes:

> In article <································@speakeasy.net>,
>  ····@rpw3.org (Rob Warnock) wrote:
>
>> Pedro Kröger <············@gmail.com> wrote:
>> | You may want to try something like this:
>> | (defmacro test (x)
>> |     `(defun ,(read-from-string (concatenate 'string (symbol-name x) "bar"))
>> |             ()
>> |        (+ 2 2)))
>> 
>> Why READ-FROM-STRING and not simply INTERN?
>
> Because if you use INTERN you need to do the right thing regarding 
> mapping case, whereas READ-FROM-STRING will handle it automatically.

... for certain uses.  I'm not sure that
  (test FOO)
is expected to define a function named |FOObar| if the READTABLE-CASE
of *READTABLE* happens to be :PRESERVE.  (Not to say that INTERN is
necessarily certain to do what the unthinking author means either, but
I don't see why READ-FROM-STRING is necessarily the right answer for
all case mappings.)

Christophe
From: CE
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <JfWdnfTsRKlCKu_ZRVn-tA@speakeasy.net>
Barry Margolin wrote:
> In article <································@speakeasy.net>,
>  ····@rpw3.org (Rob Warnock) wrote:
> 
>> Pedro Kr�ger <············@gmail.com> wrote:
>> +---------------
>> | joe wrote:
>> | > Is it possible to use a macro parameter as the basis for forming new
>> | > names within the macro?
>> | 
>> | You may want to try something like this:
>> | (defmacro test (x)
>> |     `(defun ,(read-from-string (concatenate 'string (symbol-name x) "bar"))
>> |             ()
>> |        (+ 2 2)))
>> +---------------
>>
>> Why READ-FROM-STRING and not simply INTERN?
> 
> Because if you use INTERN you need to do the right thing regarding 
> mapping case, whereas READ-FROM-STRING will handle it automatically.

You can get both!  Use format:  (intern (format nil "~S-~S" :foo :bar))

   -- MJF
From: Rob Warnock
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <evOdne0t_vxISu_Z4p2dnA@speakeasy.net>
CE <·······@hpalace.com> wrote:
+---------------
| Barry Margolin wrote:
| >····@rpw3.org (Rob Warnock) wrote:
| >> Why READ-FROM-STRING and not simply INTERN?
| > 
| > Because if you use INTERN you need to do the right thing regarding 
| > mapping case, whereas READ-FROM-STRING will handle it automatically.
| 
| You can get both!  Use format:  (intern (format nil "~S-~S" :foo :bar))
+---------------

I suggested basically the same thing in another branch of the reply tree,
namely:

    (intern (concatenate 'string (symbol-name x) (symbol-name :bar)))


-Rob

p.s. Or for a very slight performance gain:

    (intern (concatenate 'string (symbol-name x)
				 (load-time-value (symbol-name :bar))))

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Christophe Rhodes
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <sqlkst83kn.fsf@cam.ac.uk>
····@rpw3.org (Rob Warnock) writes:

> p.s. Or for a very slight performance gain:
>
>     (intern (concatenate 'string (symbol-name x)
> 				 (load-time-value (symbol-name :bar))))

This (the addition of load-time-value) looks like a performance loss
to me.  Symbols' symbol-name never changes, so any compiler worth its
salt will constant-fold calls to symbol-name with a constant argument;
however, load-time-value is not foldable in general (surprising things
can be done with make-load-form) though it probably is in this case,
so it will be executed every time for a definition of this macro which
is compiled but not file-compiled.

Christophe
From: Rob Warnock
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <qrCdnevYIoDzf-_ZRVn-uQ@speakeasy.net>
Christophe Rhodes  <·····@cam.ac.uk> wrote:
+---------------
| ····@rpw3.org (Rob Warnock) writes:
| > p.s. Or for a very slight performance gain:
| >     (intern (concatenate 'string (symbol-name x)
| > 				 (load-time-value (symbol-name :bar))))
| 
| This (the addition of load-time-value) looks like a performance loss
| to me.  Symbols' symbol-name never changes, so any compiler worth its
| salt will constant-fold calls to symbol-name with a constant argument;
| however, load-time-value is not foldable in general (surprising things
| can be done with make-load-form) though it probably is in this case,
| so it will be executed every time for a definition of this macro which
| is compiled but not file-compiled.
+---------------

Hmmm... I'm not sure that's correct. The CLHS for "LOAD-TIME-VALUE" says:

    If a LOAD-TIME-VALUE expression appears within a function
    compiled with COMPILE, the form is evaluated at compile time in
    a null lexical environment. The result of this compile-time
    evaluation is treated as a literal object in the compiled code.

How can a literal object be "executed every time"?

Now if it's not even *compiled*, then it certainly *might* be
evaluated every time, but even that is not mandated:

    If a LOAD-TIME-VALUE expression is processed by EVAL, "form" is
    evaluated in a null lexical environment, and one value is returned.
    Implementations that implicitly compile (or partially compile)
    expressions processed by EVAL might evaluate "form" only once,
    at the time this compilation is performed.

Finally, I just noticed that in the particular case we're discussing,
it would probably be desirable to specify the optional READ-ONLY-P
argument as T, in the hopes that that would encourage sharing and/or
single-evaluation:

    "Read-only-p" designates whether the result can be considered a
    constant object. If T, the result is a read-only quantity that can,
    if appropriate to the implementation, be copied into read-only space
    and/or "coalesced" with similar constant objects from other programs.
    If NIL (the default), the result must be neither copied nor coalesced;
    it must be considered to be potentially modifiable data.

That is:

    (load-time-value (symbol-name :bar) t)

[And yes, I understand that the string that SYMBOL-NAME returns
is already supposed to be treated as immutable, but specifying
READ-ONLY-P as T at least tells the compiler you're promising
to honor that. I'm not sure this is needed, but it might help
with some compiler(s).]


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Christophe Rhodes
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <sqhd3h80yl.fsf@cam.ac.uk>
····@rpw3.org (Rob Warnock) writes:

> Christophe Rhodes  <·····@cam.ac.uk> wrote:
> +---------------
> | ····@rpw3.org (Rob Warnock) writes:
> | > p.s. Or for a very slight performance gain:
> | >     (intern (concatenate 'string (symbol-name x)
> | > 				 (load-time-value (symbol-name :bar))))
> | 
> | This (the addition of load-time-value) looks like a performance loss
> | to me.  Symbols' symbol-name never changes, so any compiler worth its
> | salt will constant-fold calls to symbol-name with a constant argument;
> | however, load-time-value is not foldable in general (surprising things
> | can be done with make-load-form) though it probably is in this case,
> | so it will be executed every time for a definition of this macro which
> | is compiled but not file-compiled.
> +---------------
>
> Hmmm... I'm not sure that's correct. The CLHS for "LOAD-TIME-VALUE" says:
>
>     If a LOAD-TIME-VALUE expression appears within a function
>     compiled with COMPILE, the form is evaluated at compile time in
>     a null lexical environment. The result of this compile-time
>     evaluation is treated as a literal object in the compiled code.
>
> How can a literal object be "executed every time"?

Oh, whoops.  My apologies, my memory about load-time-value was wrong.
Sorry about that.

Christophe
From: Mark Wooding
Subject: Re: Manipulating macro parameters
Date: 
Message-ID: <slrne75qbo.1dq.mdw@metalzone.distorted.org.uk>
CE <·······@hpalace.com> wrote:

> You can get both!  Use format:  (intern (format nil "~S-~S" :foo :bar))

This breaks when *PRINT-CASE* is :DOWNCASE.  I don't like Lisp shouting
at me.  You could chuck in ··@(...~), but that doesn't preserve the
existing case of the input symbols.

(defun glue-symbols (&rest syms)
  (intern (apply #'concatenate 'string (mapcar #'string syms))))

-- [mdw]
From: joe
Subject: THANKS was: re: Manipulating macro parameters
Date: 
Message-ID: <2006052219061316807-nomail@nomailcom>
Hey everybody - thanks for helping me with this problem!
Take  care
    JOE


On 2006-05-21 18:22:46 -0700, joe <······@nomail.com> said:

> Hi all -
> 
> Is it possible to use a macro parameter as the basis for forming new 
> names within the macro? In the following example I would like to append 
> 'bar' to the macro parameter x, to create a new defun:
> 
> (defmacro test (x)
>  `(defun ,x[+bar] () (+ 2 2)))
> 
> 
> So that:
> 
> (test foo)
> 
> 
> Results in:
> 
> (defun foobar () (+ 2 2))
> 
> 
> Any help/guidance would be greatly appreciated, and sorry in advance if 
> I missed the incredibly obvious.
>       JOE