This is a read-only archive of lispforum.com. The forum was locked to new users and posts and is preserved here as static HTML from a database snapshot taken on 2019-09-07.

Behaviour of EVAL inside LET

15 posts · 11933 views

I found the following example of a strange behaviour of command EVAL inside LET constructions. Executing the code
(setf z 666)
(let ((z 14))
    (print z)
    (eval '(setf www z)) 
  )
results in printing the value 14 of the variable z inside LET construction, but the variable www takes the value 666, not 14!

A very similar code
(setf z 666)
(let ((z 14))
    (print z)
    (setf www z)
  )
results in the value 14 of the variable www, as expected.
Can someone explain this situation?
To understand LISP, you must first understand LISP.

Re: Behaviour of EVAL inside LET

Because eval evaluates its argument in the null lexical environment.
The environment can be captured to an environment object by a macro then to be passed to another macro but the environment object is implementation-dependent so you can't easily build lexical environment from that.
cl-2dsyntax is my attempt to create a Python-like reader. My mirror of CLHS (and the dark themed version). Temporary mirrors of aferomentioned: CLHS and a dark version.

Re: Behaviour of EVAL inside LET

Thank you for the explanation!
U found the right code which does what expected and still uses EVAL:
(setf z 666)
(let ((z 14))
    (eval `(setf www ',z))
  )
It is a bit involved combination of ` ' and , characters before variable z but the result is the value 14 of variable www, as expected!
To understand LISP, you must first understand LISP.

Re: Behaviour of EVAL inside LET

abvgdeika wrote:I found the following example of a strange behaviour of command EVAL inside LET constructions. Executing the code
(setf z 666)
(let ((z 14))
    (print z)
    (eval '(setf www z)) 
  )
results in printing the value 14 of the variable z inside LET construction, but the variable www takes the value 666, not 14!

A very similar code
(setf z 666)
(let ((z 14))
    (print z)
    (setf www z)
  )
results in the value 14 of the variable www, as expected.
Can someone explain this situation?
Try this in your lisp:
(defun try (x)
(print z))

(setf z 666)
(let ((z 14))
 (try))
Do you know why it prints 666 instead of 14? The reason is the same as why your code acts the way it does (but note that it doesn't have to...what you've written is not strictly legal in Common Lisp; in my implementation it sets www to 14, and (try) prints 14. Why? Because (setf z 666) doesn't have any meaning when z doesn't exist -- you need a DEFVAR or DEFPARAMETER, or a LET or something, to make a variable called z before you can say (setf z 666), and you haven't got one.)

Re: Behaviour of EVAL inside LET

Eval can be useful if you want to write your own repl or interpreter. But in 99% of the cases where beginners tend to use eval there is a better solution using functional objects and funcall. It also executes much faster than eval.
(setf z 666)
(let ((z 14))
    (print z)
    (funcall #'(lambda () (setf www z))))

Re: Behaviour of EVAL inside LET

The hyperspec says it evaluates the expression in the current dynamic environment, but the null lexical environment.

Thus:
(defparameter z 666) ; z is dynamicly scoped 
(let ((z 14)) 
  (eval '(setf www z)))

www
==> 14
Since z is dynamicly scoped and not lexical.
So what let is shadowing is important.
I'm the author of two useless languages that uses BF as target machine.
Currently I'm planning a Scheme compiler :p

Re: Behaviour of EVAL inside LET

Thanks for all answers!
I still have some problems with lexical closures, now even without "eval" operator.
When executing the following code
(setf a 666)
(setf command '(+ a 1) )
  
(let ((a 13))
  (funcall    (list 'lambda () command)     )   
)
the result of the last "let" construction is 667 but not 14 as expected.
My question: is there any clever way to "execute" the variable COMMAND inside "let" constiruction
so that this execution uses the current value of variable "A" which is 13?
To understand LISP, you must first understand LISP.

Re: Behaviour of EVAL inside LET

(list 'lambda () command) returns a lambda-expression not a evaluated lambda-expression so this won't work in many CL-implementations.
As mentioned before; If you declare a dynamically scoped it will do what you want.
(defparameter a 666)
(setf command (lambda () (+ a 1)))
  
(let ((a 13))
  (funcall command) ==> 14
)

;; OR
(defparameter a 666)
(defun command () (+ a 1))
  
(let ((a 13))
  (command) ==> 14
)
I'm the author of two useless languages that uses BF as target machine.
Currently I'm planning a Scheme compiler :p

Re: Behaviour of EVAL inside LET

After some experiments I found a right replacement of EVAL operator which works as expected inside lexical closures. This is the following macro:
(defmacro true-eval (command-expression)
  `(macrolet ((evaluate () ,command-expression))
     (evaluate)
     ))
Here is a testing code:
(setf command '(+ c j) )
(setf c 666)
(loop for j from 1 to 3 do
      (let ((c -13))
        (print (true-eval command) )
        ) )
Resulting printed sequence of values is -12 -11 -10 as expected!
Even a nested call of "true-eval" works:
(setf inner-command '(+ c j) )
(setf outer-command '(* 10 (true-eval inner-command))  )
(setf c 666)
(loop for j from 1 to 3 do
      (let ((c -13))
        (print (true-eval outer-command) )
        )
      )
Resulting printed sequence is -120 -110 -100 as expected!
To understand LISP, you must first understand LISP.

Re: Behaviour of EVAL inside LET

Why don't you use simply quasiquotation in this case?
(loop for i below 10 do (print (eval `(+ 20 ,i))))
Because true-eval isn't really a right replacement, let me show it:
(loop for i below 3 do (format t "~a> ~a~%" i (eval (read))))
vs.
(loop for i below 3 do (format t "~a> ~a~%" i (true-eval (read))))
The macroexpansion works during the compile time.
// Add finish-output if it's needed.
cl-2dsyntax is my attempt to create a Python-like reader. My mirror of CLHS (and the dark themed version). Temporary mirrors of aferomentioned: CLHS and a dark version.

Re: Behaviour of EVAL inside LET

The discussion in this topic is aimed at better understanding how the principle "there is no difference between code and data in LISP" works in practice.
My intention was to "execute" comand-variables containing LISP code as their values (like variable "command") so that all variables which appear in this code assume local values within current lexical environment during the execution. And macro "true-eval" does this job! It may fail in some other situations like in your input-output operators (in some implementations). In my implementation (Allegro CL),
both your input-output codes with EVAL and TRUE-EVAL work identically without problems.
To understand LISP, you must first understand LISP.

Re: Behaviour of EVAL inside LET

Yes, for that macros are good.
But I've wanted to point the difference between a runtime evaluation and a macroexpansion out (beacuse I didn't know you don't want the normal evaluation). Try in Allegro CL to factor out what was in the loop.
(defun counted-result (i) (format t "~a> ~a~%" i (eval (read))))
(loop for i below 3 do (counted-result i))
vs.
(defun counted-result (i) (format t "~a> ~a~%" i (true-eval (read))))
(loop for i below 3 do (counted-result i))
At the second snippet insert the top-level forms one by one and maybe use compile which can be used by program, so it's relevant.
cl-2dsyntax is my attempt to create a Python-like reader. My mirror of CLHS (and the dark themed version). Temporary mirrors of aferomentioned: CLHS and a dark version.

Re: Behaviour of EVAL inside LET

I am not so advanced LISP user to understand
the difference between a runtime evaluation and a macroexpansion out
(:-))))
But macro TRUE-EVAL has indeed a strange behaviour. It cannot be applied to formal variables inside function definitions, an attempt to compile
(defun t-eval (x) (true-eval x) ) 
gives an error unless "x" already has some value.
My suggestion to those who read this forum and who plan to improve/better implement such a great langage as LISP is to take more attention to the evaluation operations.
To understand LISP, you must first understand LISP.

Re: Behaviour of EVAL inside LET

Because the x gets evaluated during macroexpansion of the evaluate in macrolet, so you should have it quoted:
(defun t-eval (x) (true-eval 'x))
cl-2dsyntax is my attempt to create a Python-like reader. My mirror of CLHS (and the dark themed version). Temporary mirrors of aferomentioned: CLHS and a dark version.

Re: Behaviour of EVAL inside LET

abvgdeika wrote:The discussion in this topic is aimed at better understanding how the principle "there is no difference between code and data in LISP" works in practice.
My intention was to "execute" comand-variables containing LISP code as their values (like variable "command") so that all variables which appear in this code assume local values within current lexical environment during the execution.
You can't do that, as a general rule. You're confusing symbols and variables -- they're not the same thing (except for "special" variables). Symbols are data objects used to name variables; a variable is just a memory address -- there's no way to link a symbol to an address in Lisp (you might be able to through the debugger interface, etc.), so you can't turn a symbol coming from outside into the same variable that was named by that symbol in a piece of source code. (And if you could, you'd break all sorts of things...)