Functional programming 为什么不在方案中进行评估?
我正在使用DrRacket环境来尝试Scheme语言 我将总和+1定义如下:Functional programming 为什么不在方案中进行评估?,functional-programming,scheme,expression,lisp,racket,Functional Programming,Scheme,Expression,Lisp,Racket,我正在使用DrRacket环境来尝试Scheme语言 我将总和+1定义如下: (define sum+1 '(+ x y 1)) 我想知道为什么下面的表达式不计算: (let ([x 1] [y 2]) (eval sum+1)) 而这样做会返回正确的值: (define x 1) (define y 2) (eval sum+1) 带有let的命令不起作用的原因是let创建局部变量。这意味着它创建的变量不能从任何地方访问-只能从let的主体参数中访问 在您的示例中,您定义了: (defi
(define sum+1 '(+ x y 1))
我想知道为什么下面的表达式不计算:
(let ([x 1] [y 2]) (eval sum+1))
而这样做会返回正确的值:
(define x 1)
(define y 2)
(eval sum+1)
带有
let
的命令不起作用的原因是let
创建局部变量。这意味着它创建的变量不能从任何地方访问-只能从let
的主体参数中访问
在您的示例中,您定义了:
(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
定义并可以打印。请回答您的任何问题或反馈 使用let
的命令不起作用的原因是let
创建局部变量。这意味着它创建的变量不能从任何地方访问-只能从let
的主体参数中访问
在您的示例中,您定义了:
(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
定义并可以打印。请回答您的任何问题或反馈 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
到大多数方案实现运行代码时,局部变量通常是堆栈分配的。因此,想象一下这个代码:
(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语言只能被解释,因为它允许将宏作为第一类对象传递。这些语言在编译时是无法推理的。
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
到大多数方案实现运行代码时,局部变量通常是堆栈分配的。因此,想象一下这个代码:
(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语言只能被解释,因为它允许将宏作为第一类对象传递。这些语言在编译时是不可能推理的。这一点解释得相当好。这一点解释得相当好。非常感谢您的回答,因此“eval”无法在调用它的范围内看到定义,而只能看到全局范围内的定义。我觉得这种行为很奇怪,因为其他过程可以访问覆盖全局范围的局部范围,而eval本身是一个过程,而不是一种特殊形式,它的行为应该与所有其他过程一样!有没有理由证明这种行为是正确的?我不完全确定为什么eval的行为不像其他过程,但我最好的猜测是:eval是一个特定的函数,它要求对某些东西进行求值,因此有可能不是问(像其他函数一样),“我有什么信息可以解决这个问题?”它会问,“我得到了什么信息来解决这个问题?”这意味着,它需要给出具体的指示,而不是一个全局调用的过程。(如果这没有多大意义的话,很抱歉,在我看来这听起来很合理。)值得思考的是
eval
可以看到词汇绑定的实现将如何工作:特别是(eval(read))
应该如何工作?编译器是如何工作的?非常感谢你的回答,所以“eval”看不到我的定义