Scheme 使用当前函数进行求值';s名称空间

Scheme 使用当前函数进行求值';s名称空间,scheme,eval,racket,Scheme,Eval,Racket,以下球拍功能产生错误: reference to undefined identifier: val 这是因为eval函数查看的是全局名称空间,而不是本地函数的名称空间。如何欺骗eval使用本地函数的名称空间 (define some-eval! (lambda (val row col) (eval (list 'define 'ttboard '(list-builder val row col))) (current-namespace) )) 你的问题是针对球拍的。一般来

以下球拍功能产生错误:

reference to undefined identifier: val
这是因为eval函数查看的是全局名称空间,而不是本地函数的名称空间。如何欺骗eval使用本地函数的名称空间

(define some-eval!
  (lambda (val row col)
    (eval (list 'define 'ttboard '(list-builder val row col))) (current-namespace) ))

你的问题是针对球拍的。一般来说,不同的Scheme实现有不同的方法来解决这个问题,但在几乎所有情况下,您都不会像您试图做的那样使用
eval
来处理本地绑定。但具体到球拍案例,您应该阅读《球拍指南》中的-,它解释了为什么事情不能按您希望的方式工作,并说明了如何使模块作用域工作

正如一个简短的总结——
eval
看不到本地绑定的原因是,这意味着
(lambda(x)x)
(lambda(y)y)
不能编译为同一个函数,因为名称可能会有所不同。您可能认为编译可能取决于函数内部是否使用了
eval
,但这是编译时无法确定的。例如:

(define (foo f) (let ([x 1]) (f 'x)))
(foo eval)
在这种情况下,编译器无法判断
foo
是否会被
eval
调用

最后,在其他试图解决
eval
问题的语言中也存在类似的困难。例如,在JS中,
eval
是一个神奇的东西,它可以影响函数的编译方式,例如:

function foo(x) { alert("x = " + eval("x")); }
将实际工作——但它需要
eval
实际存在于函数体中。如果不这样做,事情就会破裂。例如,此代码:

function foo(x,f) { alert("x = " + f("x")); }
foo(123,eval);
在Fx中对我有效,但在Chrome中失败,表示未定义
x
。如果这还不足以证明混乱,请考虑如下:

function foo(x,f) { alert("x = " + f("x")); }
var x = 456;
foo(123,eval);

在Chrome和Fx中显示456。

我认为,对于您想要做的事情,在表达式合成时设置
val
的值就足够了,而不是让解释器在计算时获取
val
等的值(在Racket中不可能)


请注意,几乎可以肯定有一种更好、更简洁的方法来完成您在不使用
eval
的情况下试图完成的任务,当然,除非您这样做是为了练习使用
eval

您可以提前定义
ttboard
,然后设置
it:

(define ttboard #f)
(define create-board
  (lambda (val row col)
    (set! ttboard (list-builder val row col))))

这样,您就可以清楚地知道
ttboard
是一个全局变量,而不是在eval'd子句中模糊其定义。

正如Eli所指出的,一般来说,使用
eval
无法访问词汇环境。但是,我相信此解决方案可以满足您的要求:

#lang racket/load

(define some-eval!
  (lambda (val row col)
    (namespace-set-variable-value! 'val val)
    (namespace-set-variable-value! 'row row)
    (namespace-set-variable-value! 'col col)
    (eval (list 'define 'ttboard '(list-builder val row col)) 
          (current-namespace))))
(define list-builder list)
(some-eval! 1 2 3)
(display ttboard)

谢谢你的回复,但我还是不知所措。如果不使用全局定义,我无法解释此代码,有其他方法吗?我还读了那篇关于敲诈的文章,他们完全忽视了我所处的明显情况,这让我很生气。(1)再次阅读我上面关于为什么不可能做到这一点的简短解释;(2) 再次阅读指南页——它确实谈到了“你的明显案例”,事实上,这正是第一节(15.1.1)所说的,这一部分有一个很好的结论,就是什么使它不可能。@Eli Barzilay是的,确切地说,这两个来源只是解释说,除非我做一个全局定义,否则我试图做的是不可能的。@Rook:嗯,我想你可以从头开始编写自己的Scheme解释器,以你想要的方式处理
eval
。这只是“不可能”的某些值的“不可能”。@erjiang是的,或者我可以使用已有的scheme风格,它有更好的文档。我实际上已经尝试过这个代码段,但它不起作用,因为列表生成器返回的内容没有定义。实际上需要eval,因为函数中的(define)将只在函数的命名空间中定义该变量,而不在全局命名空间中定义该变量。软件需求确实说明我需要修改ttboard的全局定义+谢谢你的帮助。
#lang racket/load

(define some-eval!
  (lambda (val row col)
    (namespace-set-variable-value! 'val val)
    (namespace-set-variable-value! 'row row)
    (namespace-set-variable-value! 'col col)
    (eval (list 'define 'ttboard '(list-builder val row col)) 
          (current-namespace))))
(define list-builder list)
(some-eval! 1 2 3)
(display ttboard)