Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss
Groups keyboard shortcuts have been updated
Dismiss
See shortcuts

Function composition at run time

21 views
Skip to first unread message

David E. Young

unread,
Oct 18, 2000, 3:00:00 AM10/18/00
to
Greetings. Ok, I really should know the answer to this question but the
solution is eluding me.

I've an application that needs to create a function object from a list
of forms; for example, something like:

(compose '((let ((foo "schtum")) (print foo))))

should yield the function object #'(lambda () (let ((foo "schtum"))
(print foo))).

My first attempt was the following macro:

(defmacro compose-function (expr)
(labels ((compose-body (forms &optional (body nil))
(if (null forms)
body
(compose-body (rest forms)
(nconc body
`(,(first forms)))))))
`#',(compose-body expr (list 'lambda ()))))

This actually works if invoked like:

(compose-function ((let ((foo "schtum")) (print foo))))

However, it breaks down of course with something like:

(let ((forms '((let ((foo "schtum")) (print foo)))))
(compose-function forms))

Clearly, the above doesn't work because the macro doesn't evaluate it's
argument before calling COMPOSE-BODY. And, this is where I'm stuck. I
began by doing this:

(defmacro compose-function (expr)
(let ((forms (gensym)))
`(let ((,forms ,expr))

But now what? I think I'm close; thanks for the assistance.

Regards,

--
-----------------------------------------------------------------
David E. Young
Fujitsu Network Communications "The fact that ... we still
(david...@fnc.fujitsu.com) live well cannot ease the pain of
feeling that we no longer live nobly."
-- John Updike
"Programming should be fun,
programs should be beautiful"
-- P. Graham


Rainer Joswig

unread,
Oct 18, 2000, 3:00:00 AM10/18/00
to

> I've an application that needs to create a function object from a list
> of forms; for example, something like:
>
> (compose '((let ((foo "schtum")) (print foo))))

(eval '(lambda () (let ((foo "schtum")) (print foo))))

If you want to do it at runtime, you have to use COMPILE
or EVAL.


> (defmacro compose-function (expr)
> (let ((forms (gensym)))
> `(let ((,forms ,expr))

You seem to be puzzled by the difference between runtime and
compile time. Macro Expansion is done before runtime.

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

David E. Young

unread,
Oct 18, 2000, 3:00:00 AM10/18/00
to
Rainer Joswig wrote:

> In article <39EDFA1B...@nc.rr.com>, you...@nc.rr.com wrote:
>
> > I've an application that needs to create a function object from a list
> > of forms; for example, something like:
> >
> > (compose '((let ((foo "schtum")) (print foo))))
>
> (eval '(lambda () (let ((foo "schtum")) (print foo))))
>
> If you want to do it at runtime, you have to use COMPILE
> or EVAL.
>

>


> You seem to be puzzled by the difference between runtime and
> compile time. Macro Expansion is done before runtime.

No; I know when macro expansion is performed, and I have some knowledge of
the differences between runtime and compile time (although I'm sure there
are gaps in that knowledge).

Let me be more clear. I've an embedded language that allows access to Lisp.
I must take these forms, do some variable binding work and then allow them
to be evaluated. These forms are part of a language "statement" that I
extract through parsing. I intended to build a function object by splicing
these forms in via macro expansion, hence my question.

Does that help, or am I still being vague?

Rainer Joswig

unread,
Oct 18, 2000, 3:00:00 AM10/18/00
to

> No; I know when macro expansion is performed, and I have some knowledge of
> the differences between runtime and compile time (although I'm sure there
> are gaps in that knowledge).
>
> Let me be more clear. I've an embedded language that allows access to Lisp.
> I must take these forms, do some variable binding work and then allow them
> to be evaluated. These forms are part of a language "statement" that I
> extract through parsing. I intended to build a function object by splicing
> these forms in via macro expansion, hence my question.

When do you get your code? At runtime of your Lisp program?

(defmacro do-something-with-form (form)
...)

(let ((form (get-some-form)))
(do-something-with-form form))

In above version the macro expansion happens
before runtime. So the macro sees the source
("form") and not the runtime value of form.
It is still necessary to use EVAL or COMPILE
at runtime (inside of do-something-with-form)
to get back a *function-object* .

So, let's build an example:

Say, the running Lisp program has two variables
that you want to bind:

(defparameter *user* nil) ; the script should see USER
(defparameter *server* nil) ; the script should see SERVER

One Function gives you a Lisp form. We will get it at
runtime from the user - somehow:

(defun get-lisp-form ()
(read))

Now you want to generate a Lisp function:

(defun generate-lisp-function (form)
(eval `(lambda ()
(let ((user ,*user*)
(server ,*server*))
(declare (ignorable user server))
,form))))

Now do:

(let ((new-function (let ((*user* "Rainer")
(*server* "Lispm"))
(generate-lisp-function (get-lisp-form)))))
(funcall new-function))

And enter following code: (list 'foo (concatenate 'string user "@" server) 'bar)

David E. Young

unread,
Oct 18, 2000, 3:00:00 AM10/18/00
to
Rainer Joswig wrote:

>
> When do you get your code? At runtime of your Lisp program?
>

Forgive me Rainer; I see from my original posting where the confusion arises. The
code in question actually gets evaluated at load time. Here's an example that mimics
our embedded language:

(defmacro language-statement (name &body body)
`(parse-statement body))

and in another file perhaps:

(language-statement 'foo
(when
(condition-1)
(condition-2)
then


(let ((foo "schtum"))
(print foo))))

Somewhere during the parsing of BODY the Lisp forms I mentioned (those appearing
after THEN) are extracted and stored away for later (i.e. actual runtime)
evaluation. After looking at some exampels in Graham's "On Lisp" I was hoping I
could splice these forms into a function object and just FUNCALL the object whenever
necessary. Perhaps I can't? Should I just store the forms and call EVAL at the
appropriate time instead?

David E. Young

unread,
Oct 18, 2000, 9:30:46 PM10/18/00
to
Rainer Joswig wrote:

>
> So, let's build an example...

Thanks very much, Rainer; it's clear to me now. Sorry, I still suffer from a lack of
clarity as to when it's appropriate to use EVAL. Much obliged for setting me
straight.

Rainer Joswig

unread,
Oct 18, 2000, 10:06:32 PM10/18/00
to

> Rainer Joswig wrote:
>
> >
> > So, let's build an example...
>
> Thanks very much, Rainer; it's clear to me now. Sorry, I still suffer from a lack of
> clarity as to when it's appropriate to use EVAL. Much obliged for setting me
> straight.

You can use EVAL when you want to use new Lisp source code at runtime
(see also: READ, LOAD, COMPILE-FILE, COMPILE).

To puzzle a bit - look at this:

(defmacro generate-function-form (form)


`(lambda ()
(let ((user ,*user*)
(server ,*server*))
(declare (ignorable user server))
,form)))

(defun generate-lisp-function (form)
(eval `(generate-function-form ,form)))

Or:

(defun generate-function-form (form)


`(lambda ()
(let ((user ,*user*)
(server ,*server*))
(declare (ignorable user server))
,form)))

(defun generate-lisp-function (form)
(eval (generate-function-form form)))


You can get around calling EVAL by writing your own interpreter for
your scripting language and call that instead (see for example
the Scheme chapters in PAIP).

Aaron Crane

unread,
Oct 18, 2000, 10:17:19 PM10/18/00
to
In article <39EE33D6...@nc.rr.com>,

"David E. Young" <you...@nc.rr.com> writes:
> I was hoping I could splice these forms into a function object and just
> FUNCALL the object whenever necessary. Perhaps I can't? Should I just
> store the forms and call EVAL at the appropriate time instead?

I suspect you're really looking for COERCE and/or COMPILE.

(let* ((f (coerce '(lambda (x) (+ x 42)) 'function))
(c1 (compile nil f))
(c2 (compile nil '(lambda (x) (+ x 42)))))
(values (functionp f)
(compiled-function-p c1)
(compiled-function-p c2)))
=> T T T

--
Aaron Crane

David E. Young

unread,
Oct 19, 2000, 3:00:00 AM10/19/00
to
Rainer Joswig wrote:

> To puzzle a bit - look at this:
>
> (defmacro generate-function-form (form)
> `(lambda ()
> (let ((user ,*user*)
> (server ,*server*))
> (declare (ignorable user server))
> ,form)))
>
> (defun generate-lisp-function (form)
> (eval `(generate-function-form ,form)))
>
> Or:
>
> (defun generate-function-form (form)
> `(lambda ()
> (let ((user ,*user*)
> (server ,*server*))
> (declare (ignorable user server))
> ,form)))
>
> (defun generate-lisp-function (form)
> (eval (generate-function-form form)))
>

So; as I read this the first case hands EVAL a DEFMACRO form; the second case gives EVAL
a LAMBDA expression. Is there a preference? Intuitively, I would think the latter.

Jochen Schmidt

unread,
Oct 19, 2000, 3:00:00 AM10/19/00
to
No I think in the first version, the "generate-function-form" is generated
at compile time (one time) and the eval gets only the result. (right?)

The second version generates the list-structure each time you call
generate-lisp-function.

The first version seems like somewhat like a inline version to the second.

Am I right???

Regards,
Jochen Schmidt

David E. Young wrote:

> Rainer Joswig wrote:
>
> > To puzzle a bit - look at this:
> >
> > (defmacro generate-function-form (form)
> > `(lambda ()
> > (let ((user ,*user*)
> > (server ,*server*))
> > (declare (ignorable user server))
> > ,form)))
> >
> > (defun generate-lisp-function (form)
> > (eval `(generate-function-form ,form)))
> >
> > Or:
> >
> > (defun generate-function-form (form)
> > `(lambda ()
> > (let ((user ,*user*)
> > (server ,*server*))
> > (declare (ignorable user server))
> > ,form)))
> >
> > (defun generate-lisp-function (form)
> > (eval (generate-function-form form)))
> >
>

> So; as I read this the first case hands EVAL a DEFMACRO form; the second
> case gives EVAL a LAMBDA expression. Is there a preference? Intuitively, I
> would think the latter.
>

> Regards,
>
> --
> -----------------------------------------------------------------
> David E. Young
> Fujitsu Network Communications "The fact that ... we still
> (david...@fnc.fujitsu.com) live well cannot ease the pain of
> feeling that we no longer live nobly."
> -- John Updike
> "Programming should be fun,
> programs should be beautiful"
> -- P. Graham
>
>
>

--


David E. Young

unread,
Oct 19, 2000, 3:00:00 AM10/19/00
to
Jochen Schmidt wrote:

> No I think in the first version, the "generate-function-form" is generated
> at compile time (one time) and the eval gets only the result. (right?)
>
> The second version generates the list-structure each time you call
> generate-lisp-function.
>
> The first version seems like somewhat like a inline version to the second.
>
> Am I right???

Here's what I get when I macroexpand each version in ACL 5.0 (Linux):

Version 1: (EVAL (EXCL::BQ-LIST 'GENERATE-FUNCTION-FORM FORM))

Version 2: (EVAL (LAMBDA NIL (LET ((USER NIL) (SERVER NIL)) (DECLARE
(IGNORABLE USER SERVER)) FORM)))

Erik Naggum

unread,
Oct 19, 2000, 3:00:00 AM10/19/00
to
* "David E. Young" <you...@nc.rr.com>

| I was hoping I could splice these forms into a function object and
| just FUNCALL the object whenever necessary.

Back in the old days, funcall (and friends) treated an argument that
was a list whose car was the symbol lambda as a function. Some
Common Lisp implementations still do that out of courtesy to the old
ways, but ANSI Common Lisp specifies that they should be coerced
into functions as if by evaluating (eval `(function ,<lambda-expr>))
before being funcallable.

| Perhaps I can't? Should I just store the forms and call EVAL at the
| appropriate time instead?

Suppose you have a list of forms to evaluate in a variable <list>.
(eval `(progn ,<list>)) will evaluate them in order. If you want a
function object, you need (eval `(function (lambda () ,<list>))),
and then you need to funcall the result. Unless you want to compile
the function, as in (compile nil `(lambda () ,<list>)), of course.
In most cases, the progn solution should be quite adequate.

#:Erik
--
I agree with everything you say, but I would
attack to death your right to say it.
-- Tom Stoppard

David E. Young

unread,
Oct 19, 2000, 3:00:00 AM10/19/00
to
Thanks to everyone for responding. I've both a decent solution and a
better understanding of macro expansion.

Regards,

0 new messages