Q: how to turn a list of symbols into a function?

1 view
Skip to first unread message

dave madden

unread,
Oct 29, 2000, 12:56:43 PM10/29/00
to
Hi. I'm new to serious lisp programming (I've fiddled with emacs lisp
for a while, though), and I'm trying to create an automatically defined
function. I've generated an appropriate function body, but I can't get
the incantation right to turn it into a function.

For example, I have:

(setq func-body (generate-2-arg-func)) => (+ arg1 arg2)

Now, I want to make a function symbol, auto-func, that takes two
arguments and returns the result of binding them into arg1 and arg2, and
executing func-body on them. That is:

(defun auto-func (arg1 arg2) ?some-magic-stuff-involving-func-body?)

(auto-func 100 200) => 300

Can anybody hit me with a clue stick about this? (I'm using CMUCL.)

Thanks!
--
header address is anti-spamified. use caution when replying by
email to <d...@loopback.mersenne.com> because my real address
omits the hostname.

Rainer Joswig

unread,
Oct 29, 2000, 1:34:34 PM10/29/00
to
In article <39FC64DB...@loopback.mersenne.com>, dave madden
<postm...@loopback.mersenne.com> wrote:

> Hi. I'm new to serious lisp programming (I've fiddled with emacs lisp
> for a while, though), and I'm trying to create an automatically defined
> function. I've generated an appropriate function body, but I can't get
> the incantation right to turn it into a function.
>
> For example, I have:
>
> (setq func-body (generate-2-arg-func)) => (+ arg1 arg2)
>
> Now, I want to make a function symbol, auto-func, that takes two
> arguments and returns the result of binding them into arg1 and arg2, and
> executing func-body on them. That is:
>
> (defun auto-func (arg1 arg2) ?some-magic-stuff-involving-func-body?)
>
> (auto-func 100 200) => 300
>
> Can anybody hit me with a clue stick about this? (I'm using CMUCL.)
>
> Thanks!

(setf func-body '(+ arg1 arg2))

(eval `(defun auto-func (arg1 arg2) ,func-body))

; (compile 'auto-func)

or

(compile 'auto-func `(lambda (arg1 arg2) ,func-body))

(auto-func 1 2)

--
Rainer Joswig, Hamburg, Germany
Email: mailto:jos...@corporate-world.lisp.de
Web: http://corporate-world.lisp.de/

Kent M Pitman

unread,
Oct 29, 2000, 1:36:56 PM10/29/00
to
dave madden <postm...@loopback.mersenne.com> writes:

> Hi. I'm new to serious lisp programming (I've fiddled with emacs lisp
> for a while, though), and I'm trying to create an automatically defined
> function. I've generated an appropriate function body, but I can't get
> the incantation right to turn it into a function.
>
> For example, I have:
>
> (setq func-body (generate-2-arg-func)) => (+ arg1 arg2)
>
> Now, I want to make a function symbol, auto-func, that takes two
> arguments and returns the result of binding them into arg1 and arg2, and
> executing func-body on them. That is:
>
> (defun auto-func (arg1 arg2) ?some-magic-stuff-involving-func-body?)
>
> (auto-func 100 200) => 300
>
> Can anybody hit me with a clue stick about this? (I'm using CMUCL.)

The normal thing to do, of course, would be

(defun auto-func (x y) (+ x y))

but I assume you're saying you want func-body to be a variable that
auto-func uses.

First know that it is bad style to use dynamic variables without *'s
on each end of the name unless you have some very important reason to
the contrary. And variables are lexical by default, so let's assume
you've arranged to declare the specialness (i.e., dynamic nature) of the
variable using defvar or defparameter or something like that, as in:

(defvar *func-body* (generate-2-arg-func))

and let's further assume that this yielded (+ *arg1* *arg2*) just for
clarity of anyone later trying to debug the system. (Better yet, you might
want it to yield:

(locally (declare (special *arg1* *arg2*))
(+ *arg1* *arg2*))

if you want generate-2-arg-func to be side-effect free and not polluting
your special variable environment as a side-effect of calling it with
debugging args. Anyway, all that given, you probably already defined
generate-2-arg-func by doing something vaguely like:

(defun generate-2-arg-func ()
(generate-n-arg-func '+ 2))

(defun generate-n-arg-func (op n-args)
(let ((vars (generate-args n-args)))
`(locally (declare (special ,@vars))
(,op ,@vars))))

(defun generate-args (n-args)
(loop for i below n-args
collect (intern (format nil "*ARG~D*" i))))

So using the same generate-args function that you surely made as a subroutine
because you knew it would be so useful (wink), you would now write:

(defun auto-func (&rest args)
(let ((n-args (length args)))
(progv (generate-args n-args) args ;bind n ars to n args
(eval *func-body*)))) ; done in the environment of the special bindings

-- -- --

The other way to write this is not to use specials at all and to compose it
only with lexicals, but that involves promoting some function from text to
a real function using EVAL of a LAMBDA expression, or using COMPILE.

In this case, you'd write:


(defun generate-2-arg-func ()
(generate-n-arg-func '+ 2))

(defun generate-n-arg-func (op n-args)
(let ((vars (generate-args n-args)))
`(,op ,@vars)))

(defun generate-args (n-args)
(loop for i below n-args
collect (intern (format nil "ARG~D" i))))

(defvar *func-body* (generate-2-arg-func))

(defun auto-func (&rest args)
(let ((n-args (length args)))
(apply (compile nil `(lambda ,(generate-args n-args)
,*func-body*))
args)))

-- -- --

But all this really begs the question of why on earth you're trying to do
this in this detached way. Can you back up from your problem and explain
why you would ever have a situation in which you knew the function body and
the args in so detached a way? It's possible to handle, as you've seen here,
but it doesn't sound very much like any likely real-world scenario.

(It doesn't sound like homework either, so hopefully my doing a fully
elaborated answer isn't spoiling anything.)

-- -- ---

Notes:

* It doesn't matter that you're using CMUCL. This kind of stuff is
identical in all implementations of CL.

* I didn't test any of the above code, so there might be bugs.
I was on my way out the door and only had 5 minutes to write this.
Hope I didn't screw up anything major. I think the overall structure
should be right. But, as they say, caveat emptor...

JP Massar

unread,
Oct 29, 2000, 1:40:55 PM10/29/00
to
On Sun, 29 Oct 2000 09:56:43 -0800, dave madden
<postm...@loopback.mersenne.com> wrote:

>Hi. I'm new to serious lisp programming (I've fiddled with emacs lisp
>for a while, though), and I'm trying to create an automatically defined
>function. I've generated an appropriate function body, but I can't get
>the incantation right to turn it into a function.
>
>For example, I have:
>
>(setq func-body (generate-2-arg-func)) => (+ arg1 arg2)
>
>Now, I want to make a function symbol, auto-func, that takes two
>arguments and returns the result of binding them into arg1 and arg2, and
>executing func-body on them. That is:
>
>(defun auto-func (arg1 arg2) ?some-magic-stuff-involving-func-body?)
>
>(auto-func 100 200) => 300
>
>Can anybody hit me with a clue stick about this? (I'm using CMUCL.)
>

Well, not a solution to exactly how you specified the problem,
but here is something that may do what you are trying to achieve:

(defun generate-2-arg-func () #'(lambda (x y) (+ x y)))
(setq func-body (generate-2-arg-func))
(defun auto-func (arg1 arg2) (funcall func-body arg1 arg2))
(auto-func 100 200) -> 300

------------------

The other way would be an awful construct:

(defun generate-2-arg-func () '(+ arg1 arg2))
(setq func-body (generate-2-arg-func))
(defun auto-func (x y)
(let ((arg1 x) (arg2 y))
(declare (special arg1 arg2))
(eval func-body)
))
(auto-func 100 200) -> 300

But I suspect this really isn't your intention.

Tim Bradshaw

unread,
Oct 29, 2000, 1:58:52 PM10/29/00
to
* dave madden wrote:
> (defun auto-func (arg1 arg2) ?some-magic-stuff-involving-func-body?)

> (auto-func 100 200) => 300

Do you want more than APPLY?

(defun auto-func (fn &rest arguments)
(apply fn arguments))

--tim

dave madden

unread,
Oct 29, 2000, 2:48:33 PM10/29/00
to
I <d...@loopback.mersenne.com> wrote:
> >
> > For example, I have:
> >
> > (setq func-body (generate-2-arg-func)) => (+ arg1 arg2)
> >
> > Now, I want to make a function symbol, auto-func, that takes two
> > arguments and returns the result of binding them into arg1 and arg2, and
> > executing func-body on them. That is:
> >
> > (defun auto-func (arg1 arg2) ?some-magic-stuff-involving-func-body?)
> >
> > (auto-func 100 200) => 300

Rainer Joswig <jos...@corporate-world.lisp.de> replied:

> (setf func-body '(+ arg1 arg2))
>
> (eval `(defun auto-func (arg1 arg2) ,func-body))
>
> ; (compile 'auto-func)
>
> or
>
> (compile 'auto-func `(lambda (arg1 arg2) ,func-body))
>
> (auto-func 1 2)

(Plus a couple of other people sent useful information.)

Thanks very much! The "compile" version worked great, and is simple
enough that I can (almost :-) understand what's going on. It looks like
I'll have to go over the quoting and unquoting mechanisms more
carefully...I'm aware of the "," operator to unquote in macros, but I
never needed it before and don't really understand how it works yet.

To respond to the questions about what I'm doing, I'm *trying* to work
through the even-parity-3 example in Koza's _Genetic_Programming_III_
book. Abstractly, it makes plenty of sense, but I'm trying to code it
up and reproduce the runs.

So, I've started by making a random code generator, which produces a
parameterized executable form based on a list of initial terminals and
functions. And, now that I can turn these forms into real functions,
I'm going to make a bunch of them and call them with various arguments
to see which ones come closest to producing the results I want. Then,
I'll work out the combination and mutation code, mate the best members
of the initial population, and check out their offspring. And so on.

Thanks again,
d.

Rainer Joswig

unread,
Oct 29, 2000, 2:58:20 PM10/29/00
to
In article <39FC7F11...@loopback.mersenne.com>, dave madden
<postm...@loopback.mersenne.com> wrote:

> Thanks very much! The "compile" version worked great, and is simple
> enough that I can (almost :-) understand what's going on. It looks like
> I'll have to go over the quoting and unquoting mechanisms more
> carefully...I'm aware of the "," operator to unquote in macros, but I
> never needed it before and don't really understand how it works yet.

It has nothing to with Macros - other than that it
is being used in macros a lot. It is simply a notation
for lists:

(list '+ pi pi)

is the same as:

`(+ ,pi ,pi)

You can think of it as follows:

In (list '+ pi pi) you have write the list
constructing function (here LIST) and you have
to quote the constants (here the symbol +).

In `(+ ,pi ,pi) you write a list template and
everything is constant - except in the places
after the minus characters - so
you are unquoting (-> forcing the evaluation
at these places). So it is kind of opposite from
the above.

Erik Naggum

unread,
Oct 30, 2000, 7:34:08 AM10/30/00
to
* Rainer Joswig <jos...@corporate-world.lisp.de>

| It is simply a notation for lists:
|
| (list '+ pi pi)
|
| is the same as:
|
| `(+ ,pi ,pi)
|
| You can think of it as follows:
|
| In (list '+ pi pi) you have write the list constructing function
| (here LIST) and you have to quote the constants (here the symbol +).
|
| In `(+ ,pi ,pi) you write a list template and everything is constant
| - except in the places after the minus characters - so you are
| unquoting (-> forcing the evaluation at these places). So it is kind
| of opposite from the above.

Except that the result of the backquote form is to be treated as a
constant. The list structure may not be modified as it might be
shared with other list structures.

(list ...) constructs a list at run-time.
`(...) constructs at least parts of the list at read-time.

#:Erik
--
Does anyone remember where I parked Air Force One?
-- George W. Bush

Reply all
Reply to author
Forward
0 new messages