racket - making vars accessible across phases
问题描述
How can I make the same variable accessible across multiple phases? For instance:
(define foo 1)
(define-for-syntax bar foo)
would complain that foo
is not defined in phase 0.
解决方案
这取决于你想要这个“变量”的目的。以下是一些选项:
- 你希望它是一个不可变的原始值。
- 您希望它是不可变的,但是像结构(不是原始数据)这样的复杂数据。
- 你希望它是可变的。
在 Leif Andersen 的评论中,她说“你不能,即使你可以,也不应该”。我猜她说的是(3)。Racket 编译器试图在“内部”Racket 运行时系统中使 (3) 成为不可能。在 Racket 文档中,这称为分离编译保证。The Independent Compilation Guarantee背后有充分的理由,以及为什么 (3) 是一个坏主意,Leif Andersen 或 Matthew Flatt 可以比我更好地解释这些原因。论文Composable and Compilable Macros: You Want It When? 和谈话球拍:元编程时间!解释其中一些原因。
但是,如果一个不可变的值就足够了,我将尝试显示 (1) 和 (2) 的答案。
1:不可变的原始数据
由于数据是不可变的,因此在不同阶段有“两个不同的标识符”是可以的。如果它们以相同的值开始,并且都没有发生突变,那么它们将保持相同的值。
(begin-for-syntax
(define foo 1))
(define foo 1)
但是,这并不能保证这两个foo
变量具有相同的值,即使它们看起来相同。"for-syntax" 环境和正常环境可能不同,并以不同方式解释这些表达式。为了确保不会发生这种情况,最好在模块中有一个单独的定义。foo
这确保它始终具有相同的一致环境。然后,对于“for-syntax”和正常方式,您可以多次要求该模块:
(module foo racket
(provide foo)
(define foo 1))
(require (for-syntax 'foo)
'foo)
2:不可变的复杂数据
有两种方法可以将其扩展到像结构这样的复杂数据:
2a:不可变的、复杂的数据、预制结构
通常结构是“生成的”,这意味着在两个不同的地方编写看起来相同的定义将生成两种不同的结构类型,并且这些结构永远不会相等
但是,结构体#:prefab
很特殊,因为如果您在两个不同的地方有相同的定义,即使在“for-syntax”和普通级别,它们也会产生相同的值。
(begin-for-syntax
(struct rgb-color [r g b] #:prefab)
(define red (rgb-color 255 0 0)))
(struct rgb-color [r g b] #:prefab)
(define red (rgb-color 255 0 0))
或者你也可以把它放在一个模块中,并在 for-syntax 和 normal 级别都需要它:
(module red racket
(provide red)
(struct rgb-color [r g b] #:prefab)
(define red (rgb-color 255 0 0)))
(require (for-syntax 'red)
'red)
2b:不可变、复杂数据、跨阶段持久结构
如果预制结构不够好,并且您希望结构感觉不像“任何事情都发生”原始数据,而更像是抽象,那么有一种方法可以在模块中定义结构,特别标记为跨阶段-执着。
然而,这并不是写作那么简单struct
。跨阶段持久的语法非常严格。据我所知,你将不得不去低级并且只使用#%kernel
像define-values
和这样的形式make-struct-type
。您的结构声明可能必须如下所示:
#lang racket/kernel
(#%declare #:cross-phase-persistent)
(define-values [_1 rgb-color rgb-color? rgb-color-ref _5]
(#%app make-struct-type 'rgb-color '#f '3 '0 '#f '() 'prefab '#f
(#%app list '0 '1 '2)))
这是一个更大的麻烦,所以更常见的解决方案是只使用预制结构。
推荐阅读
- php - 将我的子域映射到其他 mai 域
- php - 如何使用 PHP MySQL AJAX 添加动态过滤器
- elasticsearch - 使用 ElasticSearch 在静态列表中按 id 检索文档
- angular - 在 Ionic 3 中发布特殊字符时,向 API 发布请求时显示错误
- java - 布尔类型序列化和反序列化单元测试失败
- java - 为什么不能将字符串“java”添加到“字符串池”中
- c - 将 ASCII 字符串数组转换为其十六进制值数组
- .net-core - MassTransit 请求/响应是否需要微服务架构中的通用 .dll?
- php - 有没有办法为netbeans 8.2(PHP)中的if-else单行块自动添加大括号?
- javascript - 在 Sinon 中假调用具有特定参数的函数