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?

3
  • 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"? Commented May 16, 2014 at 13:21
  • 1
    Also, is this related to your earlier question, Why does SBCL eval function lose the macrolet it's running in?, in which you accepted the answer that says that eval doesn't work with lexical environments? Commented May 16, 2014 at 18:14
  • 1
    check out 'pandoric-eval' in LOL: letoverlambda.com/index.cl/guest/chap6.html#sec_7 Commented May 16, 2014 at 18:53

2 Answers 2

5

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.

Sign up to request clarification or add additional context in comments.

Comments

0

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 formresult*

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.

5 Comments

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.
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.
Outside of the debugger, there is no function you can call that can access the value of a lexical variable, given its name.
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.
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 ;-)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.