在 eval 中访问当前绑定的对象
Get access to currently bound objects in 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 中可以做这样的事情吗?
这可以使用命名空间锚点。具体来说,你想要 define-namespace-anchor
and namespace-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
本身永远不会发生变异。例如,我们可以使用 box
、unbox
和 set-box!
#lang racket
(define-namespace-anchor foo)
(define x (box 5))
(eval '(set-box! x 6) (namespace-anchor->namespace foo))
(displayln (unbox x))
这也适用于任何可变数据结构,例如向量、可变列表或可变哈希表。
警告
我知道我在这里要问的通常是邪恶的。我之所以这样问是因为我想进行测试以确保即使用户确实调用了 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 中可以做这样的事情吗?
这可以使用命名空间锚点。具体来说,你想要 define-namespace-anchor
and namespace-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
本身永远不会发生变异。例如,我们可以使用 box
、unbox
和 set-box!
#lang racket
(define-namespace-anchor foo)
(define x (box 5))
(eval '(set-box! x 6) (namespace-anchor->namespace foo))
(displayln (unbox x))
这也适用于任何可变数据结构,例如向量、可变列表或可变哈希表。