struct - 如何在 Racket 中为编译时提供结构元数据的同时覆盖结构构造函数?
问题描述
这似乎类似于重载结构构造函数之类的问题?或重载结构构造函数。但是这些问题都没有解决将重载标识符传递出模块边界的问题(通过提供它)。
例如,假设我有一个要重载构造函数的结构:
(struct fish (weight scales))
(define (make-fish [weight 5] [scales 'blue])
(fish weight scales))
现在我想提供新的构造函数,使其具有结构的名称,以使其使用完全透明:
(provide
(except-out (struct-out fish) fish)
(rename-out (make-fish fish)))
这将在大多数情况下起作用。但是可能会出现一些细微的小错误。
继承结构不再可能,也不能使用match
:
(require animals/fish)
(struct shark fish (teeth)) ;; ERROR: parent struct type not defined
(define (describe-animal animal)
(match animal
[(fish weight scales) ;; ERROR: syntax error in pattern
(format "A ~a pounds fish with ~a scales" weight scales)]
[_ "Not a fish"]))
失败:使用匹配扩展器
创建匹配扩展器(链接问题中接受的解决方案)。
它不起作用,因为您无法将匹配扩展器导出为结构。
#lang racket/base
(require
(for-syntax
racket/base
syntax/transformer)
racket/match)
(provide
(except-out (struct-out fish) fish)
(rename-out (make-fish fish)))
(struct fish (weight scales)
#:name private-fish
#:constructor-name private-fish)
(define (make-fish [weight 5] [scales 'blue])
(private-fish weight scales))
(define-match-expander fish
(lambda (stx)
(syntax-case stx ()
[(_ field ...) #'(private-fish field ...)]))
(make-variable-like-transformer #'private-fish))
你得到错误:
struct-out: 标识符未绑定到结构类型信息
在:fish
in: (struct-out fish)
问题
那么我们如何改变一个结构的构造函数,但仍然允许它被提供并用作其他结构的父级呢?
解决方案
使用元数据结构,它只是在编译时定义的结构,您可以在编译时将结构定义封装成可用于match
和继承的值。
#lang racket/base
(require
(for-syntax
racket/base
racket/struct-info
syntax/transformer)
racket/match)
(provide
(struct-out fish))
(struct fish (weight scales)
#:name private-fish
#:constructor-name private-fish)
(define (make-fish [weight 5] [scales 'blue])
(private-fish weight scales))
(begin-for-syntax
;; we define a struct that will only exist at compile time
;; and can encapsulate an identifier
(struct metadata (ctor struct-info)
#:property prop:procedure (struct-field-index ctor)
#:property prop:struct-info (lambda (self) (metadata-struct-info self))))
(define-syntax fish ;; this variable can be used like the initial struct when compiling
(metadata
(set!-transformer-procedure
(make-variable-like-transformer #'make-fish))
(extract-struct-info (syntax-local-value #'private-fish))))
该结构必须具有特定的属性:prop:procedure
,以便它仍然可以作为构造函数工作,并且prop:struct-info
,以便match
并且struct
可以在编译时获取结构信息。
笔记
请注意,在下一个版本的 Racket 中,感谢 Alex Knauth 的 PR,set!-transformer-procedure
将不再需要,您只需调用make-variable-like-transformer
.
推荐阅读
- travis-ci - 电子邮件验证错误和未触发自动构建
- c# - Json 使用动态属性名称反序列化对象数组
- c++ - 找到您正在考虑的数字的程序无法正常运行,出了什么问题?
- javascript - V8 c++ - 无法反序列化 V8 快照 blob
- javascript - 如何使用jquery预填充字段
- django - 使用 Django 上传一个大的 csv 文件(100MB)需要多长时间?
- javascript - 如何排除 html-webpack-plugin 生成的链接标签(或更具体地说是由 mini-css-extract-plugin 提取的 .css 文件)?
- python - 有什么方法可以从 pyinstaller 制作的 exe 文件中获取 python 源代码
- c# - C# 如何在 apk-xamarin 中预构建集 ip:port-iis(来自 iis-applicationhost.config)
- reactjs - 使用 redux-persist 后操作不起作用