使用当前函数的命名空间进行评估
以下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) ))
The following racket function produces the error:
reference to undefined identifier: val
This is because the eval function looks at the global namespace, not the local function's namespace. How do I trick eval into using the local function's namespace?
(define some-eval!
(lambda (val row col)
(eval (list 'define 'ttboard '(list-builder val row col))) (current-namespace) ))
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你的问题是针对 Racket 的。一般来说,不同的Scheme实现有不同的方法来解决这个问题,但在几乎所有情况下,你都不会像你试图做的那样让
eval
来处理本地绑定。但具体到 Racket 案例,您应该阅读评估部分在 Racket 指南中——它解释了为什么事情没有像你希望的那样工作,并且它展示了如何让模块范围工作。作为一个快速总结 - 本地绑定对 eval 不可见的原因是,这意味着
(lambda (x) x)
和(lambda (y ) y)
无法编译为相同的函数,因为名称可能有所不同。您可能会争辩说,编译可能取决于函数内部是否使用了 eval - 但这是无法在编译时确定的。例如:在这种情况下,编译器无法判断将使用
eval
调用foo
。最后,其他尝试解决 eval 的语言也存在类似的困难。例如,在 JS 中,
eval
是一个神奇的东西,可以影响函数的编译方式,因此类似:实际上会起作用 - 但它需要
eval
物理上存在于函数体中。如果不这样做,事情就会破裂。例如,这段代码:在 Fx 中对我有效,但在 Chrome 中失败,提示
x 未定义
。如果这还不足以证明混乱,请考虑以下内容:在 Chrome 中显示 456,在 Fx 中显示 456。
Your question is specific to Racket. In general different Scheme implementations have various approaches to this problem, but in almost all cases you will not get
eval
to handle local bindings like you're trying to do. But specific to the Racket case, you should read the evaluation section in the Racket guide -- it explains why things aren't working like you want them to, and it shows how to get the module scope to work.Just as a quick summary -- the reason local bindings are not visible to
eval
is that this means that(lambda (x) x)
and(lambda (y) y)
cannot be compiled to the same function, since the names can make a difference. You could argue that the compilation could depend on whethereval
is used inside the function or not -- but that's something that cannot be determined at compile-time. For example:In this case, there is no way for the compiler to tell that
foo
is ever going to be called witheval
.Finally, there are similar difficulties in other languages that try to tackle
eval
. For example, in JS,eval
is a magical thing that can affect the way a function is compiled, so something like:will actually work -- but it requires
eval
to be physically present in the body of the function. If that's not done, then things can break. For example, this code:works for me in Fx, but fails in Chrome, saying that
x is not defined
. And if that's not enough to demonstrate the mess, consider this:shows 456 in Chrome and in Fx.
你可以提前定义
ttboard
,然后set!
它:这样,你就可以清楚地知道
ttboard
是一个全局变量,而不是其定义在 eval'd 子句中变得模糊。You can define
ttboard
ahead of time and thenset!
it:That way, you can clearly tell that
ttboard
is a global variable, rather than having its definition obscured in an eval'd clause.我认为,对于你想做的事情,在表达式中设置
val
、row
和col
的值可能就足够了-组合时间,而不是让解释器获取 val 等的值。在评估时(在 Racket 中不可能)。请注意,几乎可以肯定有一种更好、更简洁的方法可以在不使用
eval
的情况下完成您想要完成的任务,当然,除非您这样做是为了练习使用eval
。I think that, for what you want to do, it may be enough to set the values of
val
,row
, andcol
at expression-composition time, rather than have the interpreter grab the values ofval
et al. at eval-time (impossible in Racket).Note that there is almost certainly a nicer, cleaner way to accomplish what you are trying to do without
eval
, unless, of course, you are doing this to practice usingeval
.一般来说,正如 Eli 指出的那样,无法使用
eval
访问词法环境。但是,我相信此解决方法将满足您的要求:In general, there's no way to access the lexical environment with
eval
, as Eli points out. However, I believe that this workaround will do what you want: