访问eval中当前绑定的对象

时间:2016-05-26 21:15:58

标签: racket eval

买者

我知道我在这里要问的一般是邪恶的。我特别要求,因为我想进行测试以确保我的静态分析正常工作,即使用户确实调用了eval(这个问题是关于什么)。要了解更多信息,请查看On eval in dynamic languages generally and in Racket specifically

问题

在许多其他动态语言中,我可以使用eval来修改当前环境的状态。我想在Racket中做类似的事情。例如,我想写一些类似的东西:

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

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

1 个答案:

答案 0 :(得分:3)

这可以使用命名空间锚点。具体来说,您需要define-namespace-anchornamespace-anchor->namespace

具体来说,您在要绑定语法对象的代码中使用define-namespace-anchor。并使用namespace-anchor->namespace将其转换为命名空间,可以将其缩放为current-namespace,也可以直接传入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本身永远不会发生变异。例如,我们可以使用boxunboxset-box!

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

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