问题
I am using the DrRacket environment to try out the Scheme language.
I defined sum+1 as follows:
(define sum+1 '(+ x y 1))
I was wondering why the following expression does not evaluate:
(let ([x 1] [y 2]) (eval sum+1))
whereas doing this returns the correct value:
(define x 1)
(define y 2)
(eval sum+1)
回答1:
eval
does not work with lexical variables at all unless the lexical variable was created in the same expression:
#!r7rs
(import (scheme base)
(scheme eval))
(define env (environment '(scheme base)))
(let ((x 10))
(eval 'x env)) ; ERROR! `x` is not defined
You can think of it as eval
always happening top level with the global bindings of the environment you pass to the second argument. You can perhaps trick it by passing values from your lexical environment like this:
(eval '(let ((x 10))
x)
env) ; ==> 10
(let ((x 10))
(eval `(let ((x ,x))
x)
env) ; ==> 10
By the time most Scheme implementations run code local variables are usually stack allocated. Thus something imagine this code:
(define (test v)
(display v)
(newline)
(eval 'v))
Might turn into this at runtime:
(define (test 1 #f) ; indicates 1 argument, no rest
(display (ref 0)) ; fetches first argument from stack
(newline)
(eval 'v)) ; but what is v?, certainly not the first argument
Also you can make corner cases. What happens if you mutate?
(define (test v)
(eval '(set! v 10))
v)
The structure to eval
might come from user input so it's not obvious that v
gets mutated, also many compiling Scheme implementations need to treat variables that mutate differently so it needs to know before the code runs that v
needs special treatment, but it is not decidable because the (set! v 10)
might come from the database or user input. Thus by not including local bindings you save yourself a lot of trouble and the language gets easier to optimize and compile.
There are lisp languages that can only be interpreted since it allows for passing macros as first class objects. These languages are impossible to reason about at compile time.
回答2:
The reason that the command with let
does not work is that let
creates local variables. This means that the variables it creates can NOT be accessed from just anywhere - only from within let
's body argument.
In your example, you defined:
(define sum+1 '(+ x y 1))
Then you commanded this:
(let ([x 1] [y 2]) (eval sum+1))
This doesn't work because x
and y
are only being defined in the eval
statement, not within the procedure sum+1
. This may seem counter-intuitive, but it prevents many errors with other inputs.
Your second example was:
(define x 1)
(define y 2)
(eval sum+1)
This does works because x
and y
are defined globally. This means that they CAN be accessed anywhere, and by anything. They are then applied to the sum+1
definition and are able to be printed. Please respond with any questions or feedback you have!
来源:https://stackoverflow.com/questions/46415909/why-does-this-not-evaluate-in-scheme