OK, so this is another possibly silly question, but I don't mind
feeling silly on my way to enlightenment.
Going from code to data in CL is easy; just quote the code.
But how do you go the other way, without using
the-often-warned-about EVAL?
After having done (defparameter *form* '(+ 1 2)), how do you
evaluate the value of *form* without giving in to temptation and
just go with (eval *form*)?
My example is extremely unusable, and I _don't_ know why I
would want to do such a thing, but I _do_ want to know if it's
possible, and if so, how?
Best Regards,
Mattias Nilsson.
Mattias Nilsson wrote:
> OK, so this is another possibly silly question, but I don't mind
> feeling silly on my way to enlightenment.
>
> Going from code to data in CL is easy; just quote the code.
> But how do you go the other way, without using
> the-often-warned-about EVAL?
>
> After having done (defparameter *form* '(+ 1 2)), how do you
> evaluate the value of *form* without giving in to temptation and
> just go with (eval *form*)?
>
> My example is extremely unusable, and I _don't_ know why I
> would want to do such a thing, but I _do_ want to know if it's
> possible, and if so, how?
>
CL-USER 1 > (defparameter *form* '(+ 1 2))
*FORM*
CL-USER 2 > (apply (car *form*) (cdr *form*))
3
CL-USER 3 >
Wade
> CL-USER 1 > (defparameter *form* '(+ 1 2))
> *FORM*
>
> CL-USER 2 > (apply (car *form*) (cdr *form*))
> 3
I knew I made my example too simple... What about '(* 2 (* 2 (* 2 2))),
and so on? Is recursion the only way to go?
Mattias.
In article <·······················@z14g2000cwz.googlegroups.com>,
"Mattias Nilsson" <········@bredband.net> wrote:
> > CL-USER 1 > (defparameter *form* '(+ 1 2))
> > *FORM*
> >
> > CL-USER 2 > (apply (car *form*) (cdr *form*))
> > 3
>
> I knew I made my example too simple... What about '(* 2 (* 2 (* 2 2))),
> and so on? Is recursion the only way to go?
Google for "metacircular evaluator".
--
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 ***
Mattias Nilsson wrote:
> OK, so this is another possibly silly question, but I don't mind
> feeling silly on my way to enlightenment.
>
> Going from code to data in CL is easy; just quote the code.
> But how do you go the other way, without using
> the-often-warned-about EVAL?
>
> After having done (defparameter *form* '(+ 1 2)), how do you
> evaluate the value of *form* without giving in to temptation and
> just go with (eval *form*)?
>
> My example is extremely unusable, and I _don't_ know why I
> would want to do such a thing, but I _do_ want to know if it's
> possible, and if so, how?
In most cases, you can create closures:
(defparameter *closure* (lambda () (+ 1 2)))
(funcall *closure*)
By using higher-order functions, you can create new code at runtime out
of existing building blocks:
(defun adder (x)
(lambda (y) (+ x y)))
(funcall (adder 5) 10)
Using closures like this is typically preferable because:
- Closures can be compiled upfront, so you will get efficient code.
- They can capture the lexical environment: In the adder example, the
generated closure sees the correct binding of x that is passed to the
adder function.
Using eval in conjunction with s-expressions is typically a bad idea
because here it is exactly the other way around:
- S-expressions cannot be compiled upfront. The code has to be
interpreted or compiled at runtime which is much more time consuming.
- Code executed by eval cannot capture the lexical enviroment. They can
only see global definititons and dynamically scoped variables.
Pascal
--
My website: http://p-cos.net
Closer to MOP & ContextL:
http://common-lisp.net/project/closer/
Pascal Costanza wrote:
> Using closures like this is typically preferable because:
> - Closures can be compiled upfront, so you will get efficient code.
> - They can capture the lexical environment: In the adder example, the
> generated closure sees the correct binding of x that is passed to the
> adder function.
>
> Using eval in conjunction with s-expressions is typically a bad idea
> because here it is exactly the other way around:
> - S-expressions cannot be compiled upfront. The code has to be
> interpreted or compiled at runtime which is much more time consuming.
> - Code executed by eval cannot capture the lexical enviroment. They can
> only see global definititons and dynamically scoped variables.
I guess the idea I was toying with that lead to my original question
involved code that:
- Should be compiled upfront.
- Would refuse to capture the lexical environment.
But I guess closures and a bit of discipline would do just fine.
Thanks, Pascal!
Mattias.
"Mattias Nilsson" <········@bredband.net> writes:
> Pascal Costanza wrote:
>
>> Using closures like this is typically preferable because:
>> - Closures can be compiled upfront, so you will get efficient code.
>> - They can capture the lexical environment: In the adder example, the
>> generated closure sees the correct binding of x that is passed to the
>> adder function.
>>
>> Using eval in conjunction with s-expressions is typically a bad idea
>> because here it is exactly the other way around:
>> - S-expressions cannot be compiled upfront. The code has to be
>> interpreted or compiled at runtime which is much more time consuming.
>> - Code executed by eval cannot capture the lexical enviroment. They can
>> only see global definititons and dynamically scoped variables.
>
> I guess the idea I was toying with that lead to my original question
> involved code that:
> - Should be compiled upfront.
> - Would refuse to capture the lexical environment.
>
> But I guess closures and a bit of discipline would do just fine.
> Thanks, Pascal!
Pascal gives good advice. I'd add that there are several other ways
to go from "data" to "code":
- you can write an interpreter. This allows you to do this data->code
transitions with total security: the user cannot break your program
or your system.
(Of course, if you're on the way of Greenspun City, you may be
better to use EVAL anyways.)
- you can just compile a new function:
(let ((sexp '(+ (* a x x) (* b x) c))
(args '(a b c))
(var 'x))
(let ((source (list 'lambda args (list 'lambda (list var) sexp))))
(print source)
(let ((user-function (compile nil source)))
(print (funcall (funcall user-function 2 4 -2) 3)))))
But as with EVAL, you don't capture the lexical state of your
program, of course. For this you need closures.
--
__Pascal Bourguignon__ http://www.informatimago.com/
NEW GRAND UNIFIED THEORY DISCLAIMER: The manufacturer may
technically be entitled to claim that this product is
ten-dimensional. However, the consumer is reminded that this
confers no legal rights above and beyond those applicable to
three-dimensional objects, since the seven new dimensions are
"rolled up" into such a small "area" that they cannot be
detected.
"Mattias Nilsson" <········@bredband.net> writes:
> OK, so this is another possibly silly question, but I don't mind
> feeling silly on my way to enlightenment.
>
> Going from code to data in CL is easy; just quote the code.
> But how do you go the other way, without using
> the-often-warned-about EVAL?
EVAL is exactly the right tool for the job of going from data to code.
However...
> My example is extremely unusable, and I _don't_ know why I
> would want to do such a thing, but I _do_ want to know if it's
> possible, and if so, how?
... the reason you're warned about EVAL is not because it doesn't do
its job perfectly well. You're warned about EVAL because there's
usually a better way to solve something than interpreting
s-expressions as code at runtime. Usually by throwing closures at the
problem.
--
/|_ .-----------------------.
,' .\ / | Free Mumia Abu-Jamal! |
,--' _,' | Abolish the racist |
/ / | death penalty! |
( -. | `-----------------------'
| ) |
(`-. '--.)
`. )----'
"Mattias Nilsson" <········@bredband.net> writes:
What the others said.
> Going from code to data in CL is easy; just quote the code.
> But how do you go the other way, without using
> the-often-warned-about EVAL?
EVAL is actually present in the language for a reason. Evaluating
arbitrary code is what it is supposed to do, so if you are, in fact,
writing an evaluator for some language, then EVAL may be the appropriate
choice.
The reason for the warning is that very often new lisp users become so
enamored of the function that it gets overused, an in particular, leads
to the construction of code that is then immediately EVALed, instead of
using some other, more appropriate construct.
For a completely contrived example, consider:
(defun set-global (symbol value)
(eval `(setq ,symbol ,value)))
instead of finding and using
(set symbol value)
-Tom.
--
Thomas A. Russ, USC/Information Sciences Institute
Thomas A. Russ wrote:
> The reason for the warning is that very often new lisp users become so
> enamored of the function that it gets overused, an in particular, leads
> to the construction of code that is then immediately EVALed, instead of
> using some other, more appropriate construct.
Thank you all for your answers and comments. Just one more example:
Let's say I want to write a (simple) tutorial on CL for the complete
beginner, in CL itself, showing the basic evaluation of forms. I create
a list of quoted code:
'('symbol :keyword (quote symbol) (- 3 2 1))
and want to demonstrate the evaluation of these forms by printing the
forms and their values, as well as some explanation of what is going
on. Would EVAL be appropriate in such a case?
Mattias
Mattias Nilsson wrote:
> Let's say I want to write a (simple) tutorial on CL for the complete
> beginner, in CL itself, showing the basic evaluation of forms. I create
> a list of quoted code:
> '('symbol :keyword (quote symbol) (- 3 2 1))
> and want to demonstrate the evaluation of these forms by printing the
> forms and their values, as well as some explanation of what is going
> on. Would EVAL be appropriate in such a case?
Your description is not crystal clear to me.
Are you trying to build some application that is a "visible" Common
Lisp implementation, where students type in expressions (as to the
interactive prompt of a usual CL implementation), but your application
explicitly and demonstratively breaks up the steps of the evaluation of
the expression, in order to demonstrate CL evaluation rules?
E.g. student types in (mapcar #'foo (list 1 2 3)) -->
"reading string (mapcar #'foo (list 1 2 3))"
"evaluating expression (CL:MAPCAR (CL:FUNCTION CL-USER:FOO) (CL:LIST 1
2 3))"
"CL:MAPCAR is fbound to #<function CL:MAPCAR>"
"evaluating argument (CL:FUNCTION CL-USER:FOO)" --> #<function FOO>"
"evaluating argument (CL:LIST 1 2 3) "
....
"calling #<function CL:MAPCAR>"
(foo-of-1 foo-of-2 foo-of-3)
?