From: Christian Haselbach
Subject: Using variables in a macro call
Date:
Message-ID: <ft8a67$2dr$1@online.de>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hello,
I am facing the following problem with Common Lisp's defmacro: I want to
call a macro with the contents of a variable, not with the variable itself.
For example:
(defparameter *bar* '(1 2 3))
(defmacro foo (l) (car l))
Now this won't work:
(foo *bar*)
Is there any sensible way to define *bar* or call foo in such a way that
2 would be the result.
Redifining foo to
(defmacro foo (l) `(car ,l))
is not really what I have in mind, because I really want to have the
macro do its work with the list here.
Thanks.
Regards,
Christian
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFH9530hgWPdect7uARAlOBAJ4kGu2+be5gjJwSzPAGqhO5mpeWGACeP4k+
lZY6jChVRAWxeIxHE+BZwDk=
=twnN
-----END PGP SIGNATURE-----
On Apr 5, 8:42 am, Christian Haselbach <······@muon.de> wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Hello,
>
> I am facing the following problem with Common Lisp's defmacro: I want to
> call a macro with the contents of a variable, not with the variable itself.
>
> For example:
> (defparameter *bar* '(1 2 3))
> (defmacro foo (l) (car l))
>
> Now this won't work:
> (foo *bar*)
>
> Is there any sensible way to define *bar* or call foo in such a way that
> 2 would be the result.
>
> Redefining foo to
> (defmacro foo (l) `(car ,l))
> is not really what I have in mind, because I really want to have the
> macro do its work with the list here.
Macros are expanded at compilation time; they can't use the values of
variables, as those values don't exist until runtime.
"Functions compute; macros translate." -- David Moon
What are you really trying to do here, and why do you want to use a
macro?
-- Scott
Christian Haselbach wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Hello,
>
> I am facing the following problem with Common Lisp's defmacro: I want to
> call a macro with the contents of a variable, not with the variable itself.
The problem is with yourself, namely wanting a source-code eating tool
to be a runtime value eating tool. Stop that. Indeed, the only way to
program defmacro is keeping those two times clearly separated in your mind.
http://smuglispweeny.blogspot.com/2008/03/my-nastiest-macro-ever.html
kenny
--
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/
"In the morning, hear the Way;
in the evening, die content!"
-- Confucius
Christian Haselbach <······@muon.de> writes:
> Hello,
>
> I am facing the following problem with Common Lisp's defmacro: I want to
> call a macro with the contents of a variable, not with the variable itself.
>
> For example:
> (defparameter *bar* '(1 2 3))
> (defmacro foo (l) (car l))
>
> Now this won't work:
> (foo *bar*)
>
> Is there any sensible way to define *bar* or call foo in such a way that
> 2 would be the result.
>
> Redifining foo to
> (defmacro foo (l) `(car ,l))
> is not really what I have in mind, because I really want to have the
> macro do its work with the list here.
What the other answer didn't say is that when you write:
(defparameter *bar* '(1 2 3))
the compiler learns that *BAR* is a special variable, and sets it up
so that at run-time *BAR* will be bound to (1 2 3), but it doesn't
bind it right now, at compilation time.
Si, if you want to be able to use the binding to *BAR* at compilation
time (macroexpansion being done at compilation time), you should make
sure *BAR* is bound at compilation time:
(eval-when (:compile-toplevel)
(defparameter *bar* '(1 2 3)))
So you could write something like:
(defmacro m ()
`(progn ,@(mapcar (lambda (x) `(print ',x)) *bar*)))
Of course, you still cannot pass the value of *BAR* to a macro, since
macro arguments are not evaluated. But happily there is something
that gets its argumetns evaluated: functions! So you could try:
(defun f (bar)
`(progn ,@(mapcar (lambda (x) `(print ',x)) bar)))
So now you can call:
(f *bar*)
If you wrote that directly, however, the compiler would just set
things up to have the function available at run-time, and call it at
run-time. So you must put them in the eval-when too:
(eval-when (:compile-toplevel)
(defparameter *bar* '(1 2 3))
(defun f (bar)
`(progn ,@(mapcar (lambda (x) `(print ',x)) bar)))
(print (f *bar*)))
Now, the result of function calls don't get compiled and evaluated
like the result of macro calls. You may embed this function call in a
macro:
(eval-when (:compile-toplevel)
(defparameter *bar* '(1 2 3))
(defun f (bar)
`(progn ,@(mapcar (lambda (x) `(print ',x)) bar))))
(defmacro gen-f ()
(f *bar*))
(gen-f)
C/USER[17]> (compile-file "/home/pjb/src/lisp/encours/test-ct.lisp")
;; Compiling file /home/pjb/src/lisp/encours/test-ct.lisp ...
;; Wrote file /home/pjb/src/lisp/encours/test-ct.fas
0 errors, 0 warnings
#P"/home/pjb/src/lisp/encours/test-ct.fas" ;
NIL ;
NIL
C/USER[18]> (load "/home/pjb/src/lisp/encours/test-ct.fas")
;; Loading file /home/pjb/src/lisp/encours/test-ct.fas ...
1
2
3
;; Loaded file /home/pjb/src/lisp/encours/test-ct.fas
T
C/USER[19]>
--
__Pascal Bourguignon__ http://www.informatimago.com/
"Remember, Information is not knowledge; Knowledge is not Wisdom;
Wisdom is not truth; Truth is not beauty; Beauty is not love;
Love is not music; Music is the best." -- Frank Zappa
On Apr 5, 12:36 pm, Pascal Bourguignon <····@informatimago.com> wrote:
> So, if you want to be able to use the binding to *BAR* at compilation
> time (macroexpansion being done at compilation time), you should make
> sure *BAR* is bound at compilation time:
>
> (eval-when (:compile-toplevel)
> (defparameter *bar* '(1 2 3)))
>
> So you could write something like:
>
> (defmacro m ()
> `(progn ,@(mapcar (lambda (x) `(print ',x)) *bar*)))
>
> Of course, you still cannot pass the value of *BAR* to a macro, since
> macro arguments are not evaluated. But happily there is something
> that gets its argumetns evaluated: functions! So you could try:
>
> (defun f (bar)
> `(progn ,@(mapcar (lambda (x) `(print ',x)) bar)))
>
> So now you can call:
>
> (f *bar*)
>
> If you wrote that directly, however, the compiler would just set
> things up to have the function available at run-time, and call it at
> run-time. So you must put them in the eval-when too:
>
> (eval-when (:compile-toplevel)
> (defparameter *bar* '(1 2 3))
> (defun f (bar)
> `(progn ,@(mapcar (lambda (x) `(print ',x)) bar)))
> (print (f *bar*)))
>
> Now, the result of function calls don't get compiled and evaluated
> like the result of macro calls. You may embed this function call in a
> macro:
>
> (eval-when (:compile-toplevel)
> (defparameter *bar* '(1 2 3))
> (defun f (bar)
> `(progn ,@(mapcar (lambda (x) `(print ',x)) bar))))
>
> (defmacro gen-f ()
> (f *bar*))
> (gen-f)
I don't think this reply is likely to be helpful, Pascal. Yes, you
can do this, but the odds that it's the correct approach to solve the
larger problem are about zero. An expert Lisp programmer would never
do this -- not least because it's pointless: once the call `(gen-f)'
is compiled, what it will do is to print 1, 2, and 3, no matter what
the value of `*bar*' is at runtime. So you might as well have just
written
(defmacro gen-f ()
'(progn (print 1) (print 2) (print 3)))
or, at most, used a local variable:
(defmacro gen-f ()
(let ((bar '(1 2 3)))
`(progn ,@(mapcar (lambda (x) `(print ',x)) bar))))
(Well, your version allows one thing that this doesn't: you could
compile various calls to `gen-f' under the influence of different
values of `*bar*'. But that would be bizarre -- debugging such code
would be murderously difficult.)
And anyway, your proposal doesn't even address his question: he wants
(or thinks he wants) the value to be passed in the macro invocation.
Really, the best reply is "Macros don't work that way. What are you
really trying to do?"
-- Scott
Scott Burson <········@gmail.com> writes:
> I don't think this reply is likely to be helpful, Pascal. Yes, you
> can do this, but the odds that it's the correct approach to solve the
> larger problem are about zero. An expert Lisp programmer would never
> do this -- not least because it's pointless: once the call `(gen-f)'
> is compiled, what it will do is to print 1, 2, and 3, no matter what
> the value of `*bar*' is at runtime.
Well the OP didn't mention explicitely runtime. I assume he just
wants to generate code (what is done normally by macros).
> So you might as well have just
> written
>
> (defmacro gen-f ()
> '(progn (print 1) (print 2) (print 3)))
>
> or, at most, used a local variable:
>
> (defmacro gen-f ()
> (let ((bar '(1 2 3)))
> `(progn ,@(mapcar (lambda (x) `(print ',x)) bar))))
>
> (Well, your version allows one thing that this doesn't: you could
> compile various calls to `gen-f' under the influence of different
> values of `*bar*'. But that would be bizarre -- debugging such code
> would be murderously difficult.)
>
> And anyway, your proposal doesn't even address his question: he wants
> (or thinks he wants) the value to be passed in the macro invocation.
Well, when somebody asks something impossible, it's hard to know what
he wants. Let's the OP talk again.
> Really, the best reply is "Macros don't work that way. What are you
> really trying to do?"
Yes, macros don't, functions do. When you are meta-programming, you
are not restricted to macros, you can write normal functions to be
called a compilation time.
And it's rather easier to debug than macros, since all you have are
mere functions.
--
__Pascal Bourguignon__ http://www.informatimago.com/
The mighty hunter
Returns with gifts of plump birds,
Your foot just squashed one.
From: Christian Haselbach
Subject: Re: Using variables in a macro call
Date:
Message-ID: <ft8nmg$j0r$1@online.de>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hello
> Well, when somebody asks something impossible, it's hard to know what
> he wants. Let's the OP talk again.
Yes, sorry. I did not make myself clear enough. I do in fact know that
macros do not work this way.
So let me explain my problem. I will hopefully have two macros which
take a specification and the first macro should build server side code
and the second macro should build client side code. Now I do not want
write the specification twice.
So instead of writing
(macro1 something (one two three))
(macro2 someother (one two three))
i'd like to write something like this
(... thespec (one two three))
(macro1 something thespec)
(macro2 someother thespec)
Thanks again.
Regards,
Christian
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFH99P2hgWPdect7uARAgGYAJ98anq1lvtENesSrler+R+JnPtmfQCcDu0W
s044J4IazDqBu3MS2uqEpOs=
=Wx8Z
-----END PGP SIGNATURE-----
On Apr 5, 2:33 pm, Christian Haselbach <······@muon.de> wrote:
> I will hopefully have two macros which take a specification
> and the first macro should build server side code
> and the second macro should build client side code.
> (... thespec (one two three))
> (macro1 something thespec)
> (macro2 someother thespec)
If you pass the spec to the macro through its args,
you should use hard-coded values instead of run-time
variables. Then you can insert the values into your
code by escaping them in a backquote form:
CL-USER> (defmacro def-web-code (specs)
(let ((client-mesg
(format nil
"Max clients allowed is ~D."
(car specs))))
`(defun start-server ()
(print ,client-mesg))))
DEF-WEB-CODE
CL-USER> (def-web-code (1 2 3))
START-SERVER
CL-USER> (start-server)
"Max clients allowed is 1."
If you need to vary the parameters at compile time,
then you need to use a variable that's accessible to
the macro. You can hard code a reference to the variable
into the macro, or pass the name of a special variable
to the macro as a label, and use SYMBOL-VALUE to get its
value. Just remember that the value is retrieved at
compile time, not run time. As Pascal said, you may have
to force the binding of the variable with EVAL-WHEN.
--Dan
------------------------------------------------
Dan Bensen
http://www.prairienet.org/~dsb/
On Apr 5, 2:33 pm, Christian Haselbach <······@muon.de> wrote:
> (... thespec (one two three))
> (macro1 something thespec)
> (macro2 someother thespec)
Sorry about the double post. If you want to
customize the spec at run time, you can't do
that with macros. In that case, you'll have to
define a *function* that returns another function,
which will not be defun'd. You'll have to store
your server function in a variable and funcall it.
If you can set the spec at compile time, then
you might want to define a generic macro that
takes a hard-coded spec, and defines another macro
to define the customized code:
CL-USER> (defmacro def-def-server (def-server size)
`(defmacro ,def-server (server)
(let ((client-mesg
(format nil
"Max clients allowed is ~D"
,size)))
`(defun ,server ()
(print ,client-mesg)))))
DEF-DEF-SERVER
CL-USER> (def-def-server def-small-server 1000)
DEF-SMALL-SERVER
CL-USER> (def-def-server def-big-server 1000000)
DEF-BIG-SERVER
CL-USER> (def-small-server small-server)
SMALL-SERVER
CL-USER> (def-big-server big-server)
BIG-SERVER
CL-USER> (small-server)
"Max clients allowed is 1000"
CL-USER> (big-server)
"Max clients allowed is 1000000"
--Dan
------------------------------------------------
Dan Bensen
http://www.prairienet.org/~dsb/
Christian Haselbach wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Hello
>
>
>>Well, when somebody asks something impossible, it's hard to know what
>>he wants. Let's the OP talk again.
>
>
> Yes, sorry. I did not make myself clear enough. I do in fact know that
> macros do not work this way.
>
> So let me explain my problem. I will hopefully have two macros which
> take a specification and the first macro should build server side code
> and the second macro should build client side code. Now I do not want
> write the specification twice.
>
> So instead of writing
>
> (macro1 something (one two three))
> (macro2 someother (one two three))
>
> i'd like to write something like this
>
> (... thespec (one two three))
> (macro1 something thespec)
> (macro2 someother thespec)
Are you sure you want to write a macro? Why not just make it a function
that reads the run-time spec and builds the code? If you do have a use
for a macro but you want thespec parameter to be a runtime value:
(defmacro mixed (label stuff)
`(progn
(print (list :macroexpansion-time ',label ',(type-of label)))
(print (list :runtime ,stuff (type-of ,stuff)))
(values)))
(let ((things '(a b c 1 2 3)))
(mixed hi-mom things))
hth,kenny
>
> Thanks again.
>
> Regards,
> Christian
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.6 (GNU/Linux)
> Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
>
> iD8DBQFH99P2hgWPdect7uARAgGYAJ98anq1lvtENesSrler+R+JnPtmfQCcDu0W
> s044J4IazDqBu3MS2uqEpOs=
> =Wx8Z
> -----END PGP SIGNATURE-----
--
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/
"In the morning, hear the Way;
in the evening, die content!"
-- Confucius
From: Christian Haselbach
Subject: Re: Using variables in a macro call
Date:
Message-ID: <ft8t1u$opk$1@online.de>
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
Hi
> Are you sure you want to write a macro? Why not just make it a function
> that reads the run-time spec and builds the code? If you do have a use
> for a macro but you want thespec parameter to be a runtime value:
The spec is known at compile time. Really the only thing I want is to
not write it twice. The code works perfectly if I write the spec
directly into the argument list. But since I need it for two different
things I want to declare it only once.
Regards,
Christian
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.6 (GNU/Linux)
Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org
iD8DBQFH9+lohgWPdect7uARAsKPAKDeyPhu0254DptYpRjKrdIVkOkFfwCfTXX+
/xezoXjLUkWNaoeVbPYRdik=
=pLWI
-----END PGP SIGNATURE-----
On Apr 5, 2:04 pm, Christian Haselbach <······@muon.de> wrote:
> The spec is known at compile time. Really the only thing I want is to
> not write it twice. The code works perfectly if I write the spec
> directly into the argument list. But since I need it for two different
> things I want to declare it only once.
Ah, I see. In that case, the solution Pascal offered seems
appropriate. Just be sure that when you change the spec, you
recompile everything -- otherwise your server and client could be
using different versions of your protocol.
-- Scott
On Apr 5, 3:45 pm, Scott Burson <········@gmail.com> wrote:
> On Apr 5, 2:04 pm, Christian Haselbach <······@muon.de> wrote:
>
> > The spec is known at compile time. Really the only thing I want is to
> > not write it twice. The code works perfectly if I write the spec
> > directly into the argument list. But since I need it for two different
> > things I want to declare it only once.
>
> Ah, I see. In that case, the solution Pascal offered seems
> appropriate. Just be sure that when you change the spec, you
> recompile everything -- otherwise your server and client could be
> using different versions of your protocol.
Oh, I suppose you might want to have more than one specification
extant; Pascal's approach gives you only one. In that case I would do
something like this:
(defmacro defspec (name spec)
`(setf (get ',name 'specification) ',spec))
(defmacro generate-client-code (spec-name &rest other-stuff)
(let ((spec (or (get spec-name 'specification)
(error "No spec named ~S" spec-name))))
`(... whatever ...))
Basically, you've created a new namespace in which these specification
names are bound, and then when you go to compile a `generate-client-
code' invocation, you look the name up in that namespace. You
certainly could use the symbol-value instead of a plist property, but
I think using a plist property emphasizes that this isn't an ordinary
runtime binding, and leaves the spec name free for use as a variable.
-- Scott
Scott Burson wrote:
> On Apr 5, 3:45 pm, Scott Burson <········@gmail.com> wrote:
>
>>On Apr 5, 2:04 pm, Christian Haselbach <······@muon.de> wrote:
>>
>>
>>>The spec is known at compile time. Really the only thing I want is to
>>>not write it twice. The code works perfectly if I write the spec
>>>directly into the argument list. But since I need it for two different
>>>things I want to declare it only once.
>>
>>Ah, I see. In that case, the solution Pascal offered seems
>>appropriate. Just be sure that when you change the spec, you
>>recompile everything -- otherwise your server and client could be
>>using different versions of your protocol.
>
>
> Oh, I suppose you might want to have more than one specification
> extant; Pascal's approach gives you only one. In that case I would do
> something like this:
>
> (defmacro defspec (name spec)
> `(setf (get ',name 'specification) ',spec))
>
> (defmacro generate-client-code (spec-name &rest other-stuff)
> (let ((spec (or (get spec-name 'specification)
> (error "No spec named ~S" spec-name))))
> `(... whatever ...))
That works. I just think the OP is saying multiple things can originate
from one spec, so we can do it all with one form:
(expand-my-spec one-thru-five (:expansion-option-1 42)
(one (two three) :four five))
Everything that can be done from one spec should be done from one spec
in one place. I have a readability issue with breakking this up into
multiple jobbies.
kzo
--
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/
"In the morning, hear the Way;
in the evening, die content!"
-- Confucius
On 5 Apr., 23:04, Christian Haselbach <······@muon.de> wrote:
> The spec is known at compile time. Really the only thing I want is to
> not write it twice. The code works perfectly if I write the spec
> directly into the argument list. But since I need it for two different
> things I want to declare it only once.
This may be evil and weird, and I haven't thought it through, but...
CL-USER> (defmacro fnord (list &environment env)
(let ((stuff (macroexpand list env)))
`(prog2 ,@stuff)))
FNORD
CL-USER> (macrolet ((foo ()
'((princ "; One, ")
(princ "two, ")
(princ "three."))))
(fnord (foo)))
; One, two, three.
"two, "
~ Matthias
Christian Haselbach wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> Hi
>
>
>>Are you sure you want to write a macro? Why not just make it a function
>>that reads the run-time spec and builds the code? If you do have a use
>>for a macro but you want thespec parameter to be a runtime value:
>
>
> The spec is known at compile time. Really the only thing I want is to
> not write it twice. The code works perfectly if I write the spec
> directly into the argument list. But since I need it for two different
> things I want to declare it only once.
(def-client-server-pair confirm-purchase (exchange seller buyer))
def-client-server-pair expands into two whatevers.
ie, if you are so sure they go together, you probably have some higher
order defining worth encapsulating in its own macro.
kt
--
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/
"In the morning, hear the Way;
in the evening, die content!"
-- Confucius
Christian Haselbach <······@muon.de> writes:
> Hello
>
>> Well, when somebody asks something impossible, it's hard to know what
>> he wants. Let's the OP talk again.
>
> Yes, sorry. I did not make myself clear enough. I do in fact know that
> macros do not work this way.
>
> So let me explain my problem. I will hopefully have two macros which
> take a specification and the first macro should build server side code
> and the second macro should build client side code. Now I do not want
> write the specification twice.
Clearly you don't need macros to do that. You could use one like I
proposed, but it's probably not useful. I would put the spec in a
file, and define two functions:
(compile-spec-for-client "my-app.spec")
(compile-spec-for-server "my-app.spec")
That would produce two files, spec-client.lisp and spec-server.lisp,
and compile them with cl:compile-file, and you would load one or the
other in either codebase.
Of course, if you want to have the spec compiled automatically when
you compile some source file (instead of handling it in your
loader.lisp or asd file), you could still do something like:
(eval-when (:compile-toplevel)
#+client(compile-spec-for-client "my-app.spec")
#+server(compile-spec-for-server "my-app.spec"))
(eval-when (:load-toplevel)
#+client(compile-spec-for-client "my-app-client.fas")
#+server(compile-spec-for-server "my-app-server.fas"))
#+client(defun client-code ()
(my-app:client-stuff))
#+server(defun server-code ()
(my-app:server-stuff))
--
__Pascal Bourguignon__ http://www.informatimago.com/
NOTE: The most fundamental particles in this product are held
together by a "gluing" force about which little is currently known
and whose adhesive power can therefore not be permanently
guaranteed.