1

How can I eval something a second time while keeping the lexical context?

* (defvar form '(+ 1 2))
form
* form
(+ 1 2)
* (eval form) ;; This loses the lexical scope (not an issue here)
3

For an example of the problem where the lexical scope is needed

(let ((a 1) (b 2)
      (form '(+ a b)))
  (print form)
  (print (eval form))  )
(+ a b) 
The variable A is unbound.

How do I eval that form twice in the same lexical scope?
How do eval as many times I as want (in the same lexical scope)?

Related to a previous question Why does SBCL eval function lose the macrolet it's running in?

Community
  • 1
  • 1
9mjb
  • 571
  • 3
  • 10
  • 1
    The standard `eval` doesn't let you evaluate a form in any but the null lexical environment. What do you mean by "eval twice"? You can certainly apply `eval` to the result of a call to `eval`, but I doubt that's what you mean? Can you show an example of what you'd like to be able to do, and explain how it "evals twice"? – Joshua Taylor May 16 '14 at 13:21
  • 1
    Also, is this related to your earlier question, [Why does SBCL eval function lose the macrolet it's running in?](http://stackoverflow.com/questions/17483503/why-does-sbcl-eval-function-lose-the-macrolet-its-running-in), in which you accepted the answer that says that eval doesn't work with lexical environments? – Joshua Taylor May 16 '14 at 18:14
  • 1
    check out 'pandoric-eval' in LOL: http://letoverlambda.com/index.cl/guest/chap6.html#sec_7 – Clayton Stanley May 16 '14 at 18:53

2 Answers2

6

I can be mistaken, but this seems like an XY problem. I guess your example is so simplified that the reason for your request has disappeared. Why do you need this?

Without knowing more I'm thinking you might solve this with a macro:

(defun run (expr)
  (funcall expr :run))

(defun src (expr)
  (funcall expr :src))

(defmacro expr (&body rest)
  `(let ((run (lambda () ,@rest))
         (src ',@rest))
     (lambda (m)
       (case m
         (:run (funcall run))
         (otherwise src))))))

Instead of quoting your code you feed it to expr and it creates an object. The two functions run and src takes this object and either run it in the original lexical environment (since I created a thunk) or return the source of the expression. You'r example would then be written as:

(let* ((a 1) 
       (b 2)
       (form (expr (+ a b))))
  (print (src form))
  (print (run form)))

Notice I changed from let to let* since neither a nor b is available for form. Thus the lexical environment you get is the same as if you would run your code in place of the expr form.

Eval is not used once nor twice. Perhaps CLOS could have worked just as nice.

Community
  • 1
  • 1
Sylwester
  • 47,942
  • 4
  • 47
  • 79
1

You can't use eval to evalute a form in a lexical scope. Quoth the HyperSpec page on eval (emphasis added):

Function EVAL

Syntax:

eval form ⇒ result*

Arguments and Values:

  • form—a form.
  • results—the values yielded by the evaluation of form.

Description:

Evaluates form in the current dynamic environment and the null lexical environment.

Implementations with evaluation in environment support

Although the standard eval doesn't allow you to specify a lexical environment, some implementations may provide this functionality in an implementation defined manner. For example

CLISP's ext:eval-env

3.1. Evaluation

Function (EXT:EVAL-ENV form &OPTIONAL environment). evaluates a form in a given lexical environment, just as if the form had been a part of the program that the environment came from.

Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
  • Yes, that was my question: How to eval twice in lisp (without using eval). I know I can't use eval, but what about some sort of macro, or apply, or funcall trick... or are you telling me it's impossible? .. I know it's not impossible, it's just a matter of how awkward is it. – 9mjb May 16 '14 at 06:12
  • I understand what you mean by eval'ing in a lexical environment. You can't do that. I don't know what you mean by "eval twice". You can do, e.g., `(eval (eval '(list '+ 1 2)))` and quite literally eval twice, but I doubt that that's what you mean. – Joshua Taylor May 16 '14 at 13:20
  • Outside of the debugger, there is no function you can call that can access the value of a lexical variable, given its name. – Xach May 16 '14 at 15:09
  • Xach -- That's a big part of the answer I was looking for (but didn't know it). (let ((form '(+ a b))) (let ((a 1) (b 2)) (apply (car form) (cdr form)))) .. but there is no way to eval a and b at that point... not that can see the a=1 b=2. – 9mjb May 16 '14 at 18:27
  • This answer (eval uses the null lexical environment) doesn't really address my issue (and it seems there is no way to address this issue... almost like that's what a *lexical* environment is for ;-) – 9mjb May 16 '14 at 18:31