我正在使用DrRacket环境来试用Scheme语言。
我将sum + 1定义如下:
(define sum+1 '(+ x y 1))
我想知道为什么下面的表达式没有评估:
(let ([x 1] [y 2]) (eval sum+1))
这样做会返回正确的值:
(define x 1)
(define y 2)
(eval sum+1)
答案 0 :(得分:0)
let
命令不起作用的原因是let
创建局部变量。这意味着它创建的变量不能从任何地方访问 - 只能从let
的body参数中访问。
在您的示例中,您定义了:
(define sum+1 '(+ x y 1))
然后你命令这个:
(let ([x 1] [y 2]) (eval sum+1))
这不起作用,因为x
和y
仅在eval
语句中定义,而不在过程sum+1
中定义。这可能看似违反直觉,但它可以防止其他输入的许多错误。
你的第二个例子是:
(define x 1)
(define y 2)
(eval sum+1)
这确实有效,因为x
和y
已定义全球。这意味着它们可以在任何地方和任何地方访问。然后将它们应用于sum+1
定义并且可以打印。如有任何问题或反馈,请回复!
答案 1 :(得分:0)
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
变异并不明显,许多编译方案实现需要处理变异不同的变量,因此在代码运行之前需要知道v
需要特殊处理,但它不可判定,因为(set! v 10)
可能来自数据库或用户输入。因此,通过不包括本地绑定,您可以省去很多麻烦,并且语言更容易优化和编译。
有些lisp语言只能被解释,因为它允许将宏作为第一类对象传递。这些语言在编译时无法推理。