eval 根本不适用于词法变量,除非词法变量是在同一个表达式中创建的:
#!r7rs
(import (scheme base)
(scheme eval))
(define env (environment '(scheme base)))
(let ((x 10))
(eval 'x env)) ; ERROR! `x` is not defined
您可以将其视为eval 始终与您传递给第二个参数的环境的全局绑定一起发生在顶层。您也许可以通过从您的词法环境中传递值来欺骗它,如下所示:
(eval '(let ((x 10))
x)
env) ; ==> 10
(let ((x 10))
(eval `(let ((x ,x))
x)
env) ; ==> 10
在大多数 Scheme 实现运行代码时,局部变量通常是堆栈分配的。因此,想象一下这段代码:
(define (test v)
(display v)
(newline)
(eval 'v))
在运行时可能会变成这样:
(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
您还可以制作角落案例。如果你变异了会发生什么?
(define (test v)
(eval '(set! v 10))
v)
eval 的结构可能来自用户输入,因此 v 发生变异并不明显,而且许多编译 Scheme 实现需要以不同方式处理变异的变量,因此它需要在代码运行之前知道 v需要特殊处理,但无法确定,因为(set! v 10) 可能来自数据库或用户输入。因此,通过不包括本地绑定,您可以为自己省去很多麻烦,并且语言更容易优化和编译。
有些 lisp 语言只能被解释,因为它允许将宏作为第一类对象传递。这些语言在编译时无法推理。