From: Pedro Kröger
Subject: Macro call inside dolist
Date: 
Message-ID: <1124501838.912326.192060@g14g2000cwa.googlegroups.com>
Hi,

I'm doing some experimentation with macros and the ability to create
code that generate code. This macro consumes a name and generate a
function with that name.

(defmacro make-func (name)
    `(defun ,name ()
       (format nil "the function is ~a" ,(symbol-name name))))

so running (make-func bar) will create the function bar:

(make-func bar)
(bar) => "the function is BAR"

(make-func foobar)
(foobar) => "the function is FOOBAR"

That's nice. But my goal was to define a function that reads a list of
function names and pass each one to MAKE-FUNC, something like:

(defun make-all ()
  (dolist (f '(func1 func2 func2))
    (make-func f)))

But if I run:

(make-all)
(func1)

I get "EVAL: undefined function FUNC1".

Any ideas, suggestions, and pointers are welcome.

Pedro Kröger

From: Wade Humeniuk
Subject: Re: Macro call inside dolist
Date: 
Message-ID: <A0wNe.143791$wr.82480@clgrps12>
Pedro Kr�ger wrote:
> Hi,
> 
> I'm doing some experimentation with macros and the ability to create
> code that generate code. This macro consumes a name and generate a
> function with that name.
> 
> (defmacro make-func (name)
>     `(defun ,name ()
>        (format nil "the function is ~a" ,(symbol-name name))))
> 
> Any ideas, suggestions, and pointers are welcome.
> 

There is more than 1 way

(defmacro make-funcs (&rest names)
   `(progn
      ,@(mapcar (lambda (name) `(make-func ,name)) names)))

or

(defun make-all ()
   (dolist (f '(func1 func2 func2))
     (eval `(make-func ,f))))


CL-USER 1 > (make-funcs test1 test2)
TEST2

CL-USER 2 > (test1)
"the function is TEST1"

CL-USER 3 > (test2)
"the function is TEST2"

CL-USER 4 > (make-all)
NIL

CL-USER 5 > (func1)
"the function is FUNC1"

CL-USER 6 > (func2)
"the function is FUNC2"

CL-USER 7 >

Wade
From: Coby Beck
Subject: Re: Macro call inside dolist
Date: 
Message-ID: <h8wNe.190689$9A2.33968@edtnps89>
"Pedro Kr�ger" <············@gmail.com> wrote in message 
·····························@g14g2000cwa.googlegroups.com...
=============================QUOTE
I'm doing some experimentation with macros and the ability to create
code that generate code. This macro consumes a name and generate a
function with that name.

(defmacro make-func (name)
    `(defun ,name ()
       (format nil "the function is ~a" ,(symbol-name name))))

so running (make-func bar) will create the function bar:

(make-func bar)
(bar) => "the function is BAR"

(make-func foobar)
(foobar) => "the function is FOOBAR"

That's nice. But my goal was to define a function that reads a list of
function names and pass each one to MAKE-FUNC, something like:

(defun make-all ()
  (dolist (f '(func1 func2 func2))
    (make-func f)))

But if I run:

(make-all)
(func1)

I get "EVAL: undefined function FUNC1".

Any ideas, suggestions, and pointers are welcome.
=================================END QUOTE

If this is something that will generate code at run time then you want it to 
be a function.  A macro will do its work at compile time, thus if you do not 
yet know your symbols, you can not define your functions.

So:

CL-USER 21 > (defun make-func (name)
               (setf (symbol-function name) #'(lambda () (format nil "the 
function is ~A" name)))
                name)
MAKE-FUNC

CL-USER 22 > (make-func 'bar)
BAR

CL-USER 23 > (bar)
"the function is BAR"

Then you can call it in a loop or apply it to a list or what have you.

So that is how to do what you want to do BUT!! do you really want to do it? 
IOW, what is the real problem at hand.  If your just trying things for 
learning fine, but this smells like a poor solution if it is a real problem 
mainly because you are defining named functions at runtime rather than just 
making functions to keep in a list or otherwise pass around.  Who will call 
these functions and how will they know their names?

-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: Pedro Kröger
Subject: Re: Macro call inside dolist
Date: 
Message-ID: <1124504947.276883.314650@f14g2000cwb.googlegroups.com>
Coby Beck wrote:

> So that is how to do what you want to do BUT!! do you really want to do it?
> IOW, what is the real problem at hand.  If your just trying things for
> learning fine, but this smells like a poor solution if it is a real problem
> mainly because you are defining named functions at runtime rather than just
> making functions to keep in a list or otherwise pass around.  Who will call
> these functions and how will they know their names?

First of all, thank you for your help.

You are right, this code is intended just for learning. I'm sure there
are more robust solutions for this kind of problem.

Anyway, if you must know, the idea for this started while I was doing
some examples of an html generator. Something didactic, simple, and
*not* intended to real life whatsoever, like this:

(defun b (text)
  (let ((tit "b"))
    (format nil "<~a>~a</~a>~%" tit text tit)))

(defun i (text)
  (let ((tit "i"))
    (format nil "<~a>~a</~a>~%" tit text tit)))

the idea is to be able to write code like (b (i "foo")) and generate
html. The next step was to generate these functions automatically,
since they are almost the same.

Again, I know this is not a good solution for this kind of problem
(I've been studying the source code of htmlgen in cl-http for a real
solution), I'm just using it as an excuse to learn more about lisp and
macros:-)
From: Coby Beck
Subject: Re: Macro call inside dolist
Date: 
Message-ID: <SrANe.196856$HI.125612@edtnps84>
"Pedro Kr�ger" <············@gmail.com> wrote in message 
·····························@f14g2000cwb.googlegroups.com...
> Coby Beck wrote:
>
>> So that is how to do what you want to do BUT!! do you really want to do 
>> it?
>> IOW, what is the real problem at hand.  If your just trying things for
>> learning fine, but this smells like a poor solution if it is a real 
>> problem
>> mainly because you are defining named functions at runtime rather than 
>> just
>> making functions to keep in a list or otherwise pass around.  Who will 
>> call
>> these functions and how will they know their names?
>
> First of all, thank you for your help.
>
> You are right, this code is intended just for learning. I'm sure there
> are more robust solutions for this kind of problem.
>
> Anyway, if you must know, the idea for this started while I was doing
> some examples of an html generator. Something didactic, simple, and
> *not* intended to real life whatsoever, like this:
>
> (defun b (text)
>  (let ((tit "b"))
>    (format nil "<~a>~a</~a>~%" tit text tit)))
>
> (defun i (text)
>  (let ((tit "i"))
>    (format nil "<~a>~a</~a>~%" tit text tit)))
>
> the idea is to be able to write code like (b (i "foo")) and generate
> html. The next step was to generate these functions automatically,
> since they are almost the same.

Yes, in this case you want a macro with a loop in its expansion that will 
take a list of all the similar tags you want to define (as shown in the 
other replies you got)

Cheers,

-- 
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")
From: Kent M Pitman
Subject: Re: Macro call inside dolist
Date: 
Message-ID: <uiry1mkls.fsf@nhplace.com>
"Pedro Kr�ger" <············@gmail.com> writes:

> Hi,
> 
> I'm doing some experimentation with macros and the ability to create
> code that generate code. This macro consumes a name and generate a
> function with that name.
> 
> (defmacro make-func (name)
>     `(defun ,name ()
>        (format nil "the function is ~a" ,(symbol-name name))))

This is ok.  A call to MAKE-FUNC will expand at syntax resolution
time (usually compile time, but see below) and be accessible 
thereafter.

Btw, you don't need to call symbol-name there. you can use name directly.
just quote it.  e.g.:   ',name 

> so running (make-func bar) will create the function bar:
> 
> (make-func bar)
> (bar) => "the function is BAR"

Yes, but beware.  This is only because you are working interactively.
Normally, if you compile this, 
 (MAKE-FUNC BAR) will expand in the compiler.
 The compiler will compile BAR.
 The compiler will write out a fasl file containing BAR and a call to (BAR).
 On another day in a different lisp, the loader will load that fasl file,
 instantiating the definition of BAR and then calling (BAR).

> (make-func foobar)
> (foobar) => "the function is FOOBAR"

Likewise.

> That's nice. But my goal was to define a function that reads 

The example you show does not "read" them.  Reading is an I/O
operation.  In the example you show below, it "receives them
as arguments".  Using correct terminology will keep you from
confusing yourself.

> a list of
> function names and pass each one to MAKE-FUNC, something like:
> 
> (defun make-all ()
>   (dolist (f '(func1 func2 func2))
>     (make-func f)))

Functions execute at runtime.  Macros expand at syntax time, usually
compilation time, which is before.  So there's an ordering problem
here you are not seeing.  I'll explain below.

(Btw, if you did not compile it, then the equivalent happened in the
interactive session when the evaluator first saw the form to be
evaluated.  In that case, either a compiler is called and then the
result is immediately executed, or else the form is interpreted.  But
in either case, macros get expanded prior to execution.)

> But if I run:
> 
> (make-all)
> (func1)

At compile time, you have compiled the definition of MAKE-ALL.
At that time, MAKE-FUNC is expanded.  It doesn't evaluate its argument,
so it sees an argument of F, so you have defined a function called
F.  F has been compiled and written to a file and later reloaded
when you load this file.

Or, if you're working interpreted, MAKE-ALL still gets its parts
macroexpanded and so MAKE-FUNC still defines a function F.  If interpreted,
it is permitted (but not required) to expand later, just prior to execution,
but whether it expands earlier or later, it will still not evaluate F. It
will define F when it expands and executes.

So, since you're probably working interpreted, probably the order is:

 Define MAKE-ALL.
 Expand (MAKE-FUNC F) into (DEFUN F ...).
 Call MAKE-ALL
 Thrice bind F to a value that gets ignored and in each such iteration
  execute the definition of a function F in the global environment
  (not related to the local variable F which you're ignoring).

What you actually want is EITHER
1.

 (a) not make MAKE-ALL a function but a macro.  Then it will happen at
     compile time
 (b) draw the iteration back into compile time:

  e.g.,
   (defmacro make-all ()
     `(progn ,@(mapcar (lambda (name) `(make-func ,name))
             '(func1 func2 func3))))

  This will work only if you know the names at compile time.

OR

2. not use macros at all.

   (defun make-func (name) 
     (setf (symbol-function name) 
       (lambda () 
         ; here you don't have to quote name because it's bound and gets closed over
         (format nil "the function is ~a" name))))

   (defun make-all ()
     (mapc #'make-func '(func1 func2 func3)))

I didn't test any of this.

> I get "EVAL: undefined function FUNC1".

Heh. You didn't define FUNC1.
 
> Any ideas, suggestions, and pointers are welcome.
> 
> Pedro Kr�ger

Good luck with the above.
From: Pedro Kröger
Subject: Re: Macro call inside dolist
Date: 
Message-ID: <1124506074.351454.257400@g14g2000cwa.googlegroups.com>
Kent M Pitman wrote:

> The example you show does not "read" them.  Reading is an I/O
> operation.  In the example you show below, it "receives them
> as arguments".  Using correct terminology will keep you from
> confusing yourself.

you are right, thanks for correcting my sloppy terminology.

> What you actually want is EITHER
> 1.
>
>  (a) not make MAKE-ALL a function but a macro.  Then it will happen at
>      compile time
>  (b) draw the iteration back into compile time:
> [...]
> 2. not use macros at all.

Thank you for your thoughtfully answer. It helped me to understand
more about macros and things to have in mind while using them. I have
already read about the differences between syntax time, compile time,
and runtime but this is the kind of thing that will become natural to
me after I write more code and study more (and ask more questions here
:-))


Pedro Kröger
From: Peter Seibel
Subject: Re: Macro call inside dolist
Date: 
Message-ID: <m21x4ppa7c.fsf@gigamonkeys.com>
"Pedro Kr�ger" <············@gmail.com> writes:

> Hi,
>
> I'm doing some experimentation with macros and the ability to create
> code that generate code. This macro consumes a name and generate a
> function with that name.
>
> (defmacro make-func (name)
>     `(defun ,name ()
>        (format nil "the function is ~a" ,(symbol-name name))))
>
> so running (make-func bar) will create the function bar:
>
> (make-func bar)
> (bar) => "the function is BAR"
>
> (make-func foobar)
> (foobar) => "the function is FOOBAR"
>
> That's nice. But my goal was to define a function that reads a list of
> function names and pass each one to MAKE-FUNC, something like:
>
> (defun make-all ()
>   (dolist (f '(func1 func2 func2))
>     (make-func f)))
>
> But if I run:
>
> (make-all)
> (func1)
>
> I get "EVAL: undefined function FUNC1".
>
> Any ideas, suggestions, and pointers are welcome.

The key thing here is that macros always operate on the literal forms
you give them. You would probably expect:

 (make-func f)

at the top-level to define a function named F, just like

  (make-func bar)

defines a function named BAR.

It's no different when you put that form in some other code. To get
what you want you need MAKE-ALL to be a macro, i.e. you need to use a
loop as part of the macro expansion code to generate multiple calls to
MAKE-FUNC, something like this:

 (defmacro make-all (&rest names)
   `(progn ,@(loop for name in names collect `(make-func ,name))))

If you want to read more about this you might want to look at the book
listed in my .sig.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Pedro Kröger
Subject: Re: Macro call inside dolist
Date: 
Message-ID: <1124635940.705879.8800@f14g2000cwb.googlegroups.com>
Peter Seibel wrote:

> If you want to read more about this you might want to look at the
> book listed in my .sig.

Thank you for your answer. I'm reading PCL already. I'm finishing
chapter 7 and will start chapter 8 soon.

I know you listen to this all the time, but PCL is a *great* book.
I was blown by chapter 3 (you manage to explain macros very easily and
from the very beginning)!

Cheers,

Pedro Kröger
From: Peter Seibel
Subject: Re: Macro call inside dolist
Date: 
Message-ID: <m2pss7usxi.fsf@gigamonkeys.com>
"Pedro Kr�ger" <············@gmail.com> writes:

> Peter Seibel wrote:
>
>> If you want to read more about this you might want to look at the
>> book listed in my .sig.
>
> Thank you for your answer. I'm reading PCL already. I'm finishing
> chapter 7 and will start chapter 8 soon.
>
> I know you listen to this all the time, but PCL is a *great* book.

And yet ... I never get tired of hearing it. ;-) Thanks.

-Peter

-- 
Peter Seibel           * ·····@gigamonkeys.com
Gigamonkeys Consulting * http://www.gigamonkeys.com/
Practical Common Lisp  * http://www.gigamonkeys.com/book/
From: Pedro Kröger
Subject: Re: Macro call inside dolist
Date: 
Message-ID: <1124645782.382083.123460@g14g2000cwa.googlegroups.com>
Peter Seibel wrote:
> And yet ... I never get tired of hearing it. ;-) Thanks.

That's good, because you'll be hearing it a lot, for a long time :-)

In fact, was your book that turned me into CL. I was mostly in the
scheme camp (I still like scheme a lot, though) and from time to time I
had small "language crisis" and couldn't figure out if I should swich
to CL or not. After reading the firsts chapters of PCL I was sold to CL
:-)

Cheers,

Pedro Kröger