这似乎类似于Overloading a struct constructor?或Overloading a struct constructor之类的问题。但是这些问题都没有解决将重载标识符传递到模块边界之外(通过提供它)的问题。
例如,假设我有一个要重载构造函数的结构:
(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"]))
创建匹配扩展器(链接的问题中可接受的解决方案)。
这将无法正常工作,因为您无法将Match-Expander导出为结构。
#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:标识符未绑定到结构类型信息
于:鱼
输入:(禁止输出的鱼)
那么我们如何更改一个结构的构造函数,但仍然允许它在其他结构中提供并用作父结构?
答案 0 :(得分:3)
使用元数据结构(它只是在编译时定义的结构),您可以在编译时将结构定义封装到一个可用于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
。