Functional programming 为什么不在方案中进行评估?

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

我正在使用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
的主体参数中访问

在您的示例中,您定义了:

(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”看不到我的定义