Racket 获取对eval中当前绑定对象的访问权限 警告

Racket 获取对eval中当前绑定对象的访问权限 警告,racket,eval,Racket,Eval,我知道我要问的问题通常是邪恶的。我这样问是因为我想做一些测试,以确保即使用户调用eval(这个问题是关于什么的),静态分析也能正常工作。要了解更多信息,请查看 问题: 在许多其他动态语言中,我可以使用eval修改当前环境的状态。我想在球拍上做一些类似的事情。例如,我想写一些类似于: #lang racket (define x 5) (eval '(set! x 6)) (displayln x) 并将x设置为6。在Racket中可以这样做吗?使用名称空间锚可以这样做。具体来说,你想要和 具体

我知道我要问的问题通常是邪恶的。我这样问是因为我想做一些测试,以确保即使用户调用eval(这个问题是关于什么的),静态分析也能正常工作。要了解更多信息,请查看

问题: 在许多其他动态语言中,我可以使用
eval
修改当前环境的状态。我想在球拍上做一些类似的事情。例如,我想写一些类似于:

#lang racket
(define x 5)
(eval '(set! x 6))
(displayln x)

并将
x
设置为
6
。在Racket中可以这样做吗?

使用名称空间锚可以这样做。具体来说,你想要和

具体来说,您可以在希望绑定语法对象的代码中使用
define namespace-anchor
。您可以使用
名称空间定位->名称空间
将其转换为名称空间,该名称空间可以被参数化为
当前名称空间
,也可以直接传递到eval

您的代码如下所示:

#lang racket
(define-namespace-anchor foo)
(define x 5)
(eval '(set! x 6) (namespace-anchor->namespace foo))
(displayln x)
将给您带来以下错误:

. set!: assignment disallowed;
 cannot modify a constant
  constant: x
这实际上是因为编译器将
x
设置为静态变量,因为它认为它永远不会发生变异。(因此可以在许多地方进行优化。)

通过静态调用
set,您可以使编译器确信它将发生变异一次

#lang racket
(define-namespace-anchor foo)
(define x (void))
(set! x 5)
(eval '(set! x 6) (namespace-anchor->namespace foo))
(displayln x)
这将打印出您所期望的
6

不过请注意,这仅适用于
set。这并不意味着
x
本身永远不会变异。例如,我们可以使用
取消框
设置框

#lang racket
(define-namespace-anchor foo)
(define x (box 5))
(eval '(set-box! x 6) (namespace-anchor->namespace foo))
(displayln (unbox x))

这也适用于任何可变的数据结构,例如向量、可变列表或可变哈希表。

从这个问题来看,“即使用户这样做”中的“This”并不完全清楚。是您想要实现的示例代码还是您从用户那里收到的数据?公平地说,我已经更新了警告以使其更清楚。很可能。老实说,我从来没有真正完全理解什么时候应该是这样或那样。