From: Harley Davis
Subject: Re: Let/eval question
Date: 
Message-ID: <DAVIS.93Oct6095306@passy.ilog.fr>
In article <··········@louie.udel.edu> ······@thorin.cis.udel.edu (John Hughes) writes:

   I really ought to be able to figure this out, but can some slick genius out
   there tell me what's going on when I evaluate the expression below?

   (let ((a 1)) (eval 'a))

   I gather from Wilensky (only reference I have) that eval can't make lexical
   references outside the form for some reason. Why? Am I insane for thinking
   there is some way this could return a 1? My brain feels fried.

   I'm sure this is an ancient chestnut. A thousand pardons if I'm being 
   irritating. Reply via e-mail to avoid further irritations.

Imagine if you were programming in C, and someone said they had this
nifty C interpreter library that you could use in your C programs.  So
you do something like this:

#include <cinterp.h>

main ()
{
  int x;
  printf("x is %d\n", eval("x"));
}

What would you expect this to do, given that the guy who wrote the C
interpreter didn't touch the compiler?  How could the C interpreter,
at runtime, determine the value of a variable given its name, when the
compiler has thrown out the name and replaced it by a stack pointer?
I would expect this program to fail.

The problem is exactly the same in Lisp.  Just think of the EVAL
function in Lisp as an interpreter library added in for special cases,
like software personalization.

-- Harley Davis

--

------------------------------------------------------------------------------
nom: Harley Davis			ILOG S.A.
net: ·····@ilog.fr			2 Avenue Gallie'ni, BP 85
tel: (33 1) 46 63 66 66			94253 Gentilly Cedex, France

From: J W Dalton
Subject: Re: Let/eval question
Date: 
Message-ID: <CEHCnB.FGp@festival.ed.ac.uk>
·····@passy.ilog.fr (Harley Davis) writes:

>In article <··········@louie.udel.edu> ······@thorin.cis.udel.edu (John Hughes) writes:

>  I really ought to be able to figure this out, but can some slick genius out
>  there tell me what's going on when I evaluate the expression below?

>  (let ((a 1)) (eval 'a))

>  I gather from Wilensky (only reference I have) that eval can't make lexical
>  references outside the form for some reason. Why? Am I insane for thinking
>  there is some way this could return a 1? My brain feels fried.

>Imagine if you were programming in C [...]

Hey, it's easy to give the right answer.  But how about this:
Implement lexical scoping by using, say, an a-list, and have
EVAL look at the current a-list.  Then (eval 'a) in that
context _would_ give 1.  

In other words, we could think of there being a "current environment"
that gave the current values of all variables.  Functions would "close
over" the env in force when they were created, and when a function is
called, its "closed over" env becomes the current one.  This gives
lexical scoping.  EVAL would look at the curent env.  Indeed, if you
think of a straightforward Lisp interpreter, this could easily be made
to work.

So what's going on?

What it comes down to, I think, is that we want compilers to be able
to represent variable values in a manner that is not "inspectable" in
this way.  Since that's what C compilers do, your C example follows.

Now, suppose you -- for some reason -- _want_ some kind of 
inspectable env in Common Lisp.  How close can you get?
Well, pretty darn close.

There are three problems:

  1. Capturing variable values in a structure that can be examined.
     (For extra credit, make it possible to assign to the variables
     as well.)

  2. Finding the names of the vars to capture.

  3. Writing an EVAL that can use the sort of structure created
     in 1.

1. Can be done by using functions to access or set values.
   The environment structs would contain such functions.

3. Can be done by wrapping an appropriate SYMBOL-MACROLET around
   the expression and then calling ordinary EVAL.

That leaves 2.  If you're willing to have the user list the
variables, the problem goes away.  Otherwise, to get it really
right, you have to analyze the code.  This is tricky and comes
annoyingly close to writing a compiler.  A compromise is to
define a "visible-LET" macro (VLET) that makes available the
(names of) the vars it binds.  Taking shadowing into acount
is tricky and again requires code analysis.  But this time it's
not quite a s bad, because you only have to analyze the code
in the body of the VLET.  Anyway, for "proof of method" purposes,
we can ignore shadowing.

I have some code that does this which I can post if anyone is
interested.  Of course, it's fun to write it yourself, so you
may want to stop reading.  What follows is mostly just examples, 
but it does sort of give more things away.

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

;;; VLET is the visible LET mentioned above.  It doesn't handle
;;; shadowing.

;;; Inside a VLET, GET-ENV returns an env containing all the vars
;;; that have been bound by VLET in the scope in which GET-ENV
;;; appears.

;;; (ENCLOSE list-of-vars) returns an env for the listed vars.
;;; Both getting and setting are supported via SYMEVAL-IN-ENV
;;; and SET-IN-ENV respectively.

;;; (ENVEVAL expression env) evals the expression in the env,
;;; where the env is one returned by ENCLOSE.

> (macroexpand-1
    '(vlet ((a 1) (b 2))
       (get-env)))
(VLET-1 () ((A 1) (B 2)) (GET-ENV))
T

> (macroexpand-1 *)
(LET ((A 1) (B 2))
  (MACROLET
      ((VLET (BINDS &BODY BODY) (LIST* 'VLET-1 '(A B) BINDS BODY))
       (GET-ENV NIL (LIST 'ENCLOSE '(A B))))
    (GET-ENV)))
T

;;; As you can see, VLET defines GET-ENV to ENCLOSE the right vars.  
;;; It also redefines VLET to pass on the vars accumulated so far.
;;; So nested VLETS work.  E.g. (vlet ((a 1)) (vlet ((b 2)) (get-env)))
;;; ==> #<Lexenv ((A 1) (B 2))>.  This MACROLET redef trick is useful in
;;; a number of cases.

> (eval *)                      ; * is the result of the macroexpand-1
#<Lexenv ((A 1) (B 2))>

> (enveval 'a *)
1

;;; Now an example of ENCLOSE

> (macroexpand-1 '(enclose (a b)))
(MAKE-LEXENV 
  :NAMES '(A B) 
  :GETTER #'(LAMBDA (NAME) (ECASE NAME (A A) (B B))) 
  :SETTER #'(LAMBDA (NAME VAL)
              (ECASE NAME (A (SETQ A VAL)) (B (SETQ B VAL)))))
T

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

-- jeff
From: Harley Davis
Subject: Re: Let/eval question
Date: 
Message-ID: <DAVIS.93Oct18104607@passy.ilog.fr>
In article <··········@festival.ed.ac.uk> ····@festival.ed.ac.uk (J W Dalton) writes:

   (Harley Davis) writes:

   >(John Hughes) writes:

   >  I really ought to be able to figure this out, but can some slick
   >  genius out there tell me what's going on when I evaluate the
   >  expression below? 

   >  (let ((a 1)) (eval 'a))

   >  I gather from Wilensky (only reference I have) that eval can't
   >  make lexical references outside the form for some reason. Why? Am I
   >  insane for thinking there is some way this could return a 1? My
   >  brain feels fried. 

   >Imagine if you were programming in C [...]

   What it comes down to, I think, is that we want compilers to be able
   to represent variable values in a manner that is not "inspectable" in
   this way.  Since that's what C compilers do, your C example follows.

More precisely, we want compilers to be able to generate code which is
as efficient as C code for equivalent cases.

But one of the great things about Lisp is that it lets you write
macros like VLET.

-- Harley
--

------------------------------------------------------------------------------
nom: Harley Davis			ILOG S.A.
net: ·····@ilog.fr			2 Avenue Gallie'ni, BP 85
tel: (33 1) 46 63 66 66			94253 Gentilly Cedex, France
From: Timo Gerbes - DA Thomas
Subject: Re: Let/eval question
Date: 
Message-ID: <gerbes.749929981@taunus>
·····@passy.ilog.fr (Harley Davis) writes:


>In article <··········@louie.udel.edu> ······@thorin.cis.udel.edu (John Hughes) writes:

>   I really ought to be able to figure this out, but can some slick genius out
>   there tell me what's going on when I evaluate the expression below?

>   (let ((a 1)) (eval 'a))

>   I gather from Wilensky (only reference I have) that eval can't make lexical
>   references outside the form for some reason. Why? Am I insane for thinking
>   there is some way this could return a 1? My brain feels fried.

>   I'm sure this is an ancient chestnut. A thousand pardons if I'm being 
>   irritating. Reply via e-mail to avoid further irritations.

i don't know if my answer hits you question, but this is an solution:

(let ((a 1))  
  (declare (special a)) 
  (eval 'a))

gives you the result 1, even if you have declared (setq a 2) in the global environement.
you can combine dynamic extend (lifetime of the variable) with indefinite scope (the var
can be referenced outside its lexical scope).