类型化球拍中的自定义哈希集导致语法对象违反合同
Custom hash set in typed racket leads to contract violation with syntax objects
我有一个custom set,我想用在打字球拍上。我
要求它使用 require/typed
和 #:opaque custom-set?
操作说明。它有效,除了我在 运行 时代码失败
使用语法对象调用 custom-set?
。
我有如下内容:
#lang typed/racket/base
(module UNTYPED racket/base
(require racket/set)
(provide custom-set?
make-immutable-custom-set)
(define-custom-set-types custom-set
#:elem? identifier?
(λ (id1 id2) (eq? (syntax-e id1) (syntax-e id2)))))
(require/typed 'UNTYPED
[#:opaque MySet custom-set?]
[make-immutable-custom-set ((Listof Identifier) -> MySet)])
(custom-set? (make-immutable-custom-set (list #'foo #'bar))) ;; #t
(custom-set? '()) ;; #f
哪种类型检查 returns #t
或 #f
符合预期。
现在,如果我尝试使用语法对象调用相同的 custom-set?
谓词:
(custom-set? #'(foo bar))
然后,我得到以下合同违规而不是 #f
:
custom-set?: broke its own contract
Attempted to use a higher-order value passed as `Any` in untyped code: #<syntax:stdin:: a>
in: the 1st argument of
a part of the or/c of
(or/c
struct-predicate-procedure?/c
(-> Any boolean?))
contract from: (interface for custom-set?)
blaming: (interface for custom-set?)
对 UNTYPED
模块的相同调用有效,并且 returns #f
符合预期。你能告诉我为什么语法对象会在这里破坏契约吗?我可以解决这个问题吗?
这是一个由语法对象契约不够好引起的错误。具体来说,syntax/c
合约适用于平面合约,而 Typed Racket 希望在涉及 Any
类型时使用伴侣合约。
这里涉及的Any
是由#:opaque
引入的隐式Any
需要谓词custom-set?
。它出现在输入中,保护以类型化代码开始并以非类型化代码结束的值。由于未类型化的代码可能会尝试与类型化的高阶值混淆,因此它必须用伴侣契约包装 any-wrap/c
(Typed Racket 内部)。
any-wrap/c
用于保护潜在的高阶值,以及可能包含高阶值的容器值。如果某些部分是可变的,或者如果某些部分中有函数,则不允许未类型化代码改变该数据或调用该函数。
语法对象是容器。它们可以在 "syntax-e" 和语法属性中包含任意值。理想情况下,Typed Racket 的 any-wrap/c
合约应该将语法对象包装在保护这些地方的伴侣合约中。不幸的是,合同系统中的 syntax/c
合同还不够好。由于这种语法对象被认为是 "unsafe" 容器,如果 any-wrap/c
不能安全地包装它们,它必须引发合同错误。
我认为这个问题在未来可能得到解决的唯一方法是改进 syntax/c
以与伴侣合同一起使用。之后 any-wrap/c
可以像列表一样考虑语法对象安全容器。
我有一个custom set,我想用在打字球拍上。我
要求它使用 require/typed
和 #:opaque custom-set?
操作说明。它有效,除了我在 运行 时代码失败
使用语法对象调用 custom-set?
。
我有如下内容:
#lang typed/racket/base
(module UNTYPED racket/base
(require racket/set)
(provide custom-set?
make-immutable-custom-set)
(define-custom-set-types custom-set
#:elem? identifier?
(λ (id1 id2) (eq? (syntax-e id1) (syntax-e id2)))))
(require/typed 'UNTYPED
[#:opaque MySet custom-set?]
[make-immutable-custom-set ((Listof Identifier) -> MySet)])
(custom-set? (make-immutable-custom-set (list #'foo #'bar))) ;; #t
(custom-set? '()) ;; #f
哪种类型检查 returns #t
或 #f
符合预期。
现在,如果我尝试使用语法对象调用相同的 custom-set?
谓词:
(custom-set? #'(foo bar))
然后,我得到以下合同违规而不是 #f
:
custom-set?: broke its own contract
Attempted to use a higher-order value passed as `Any` in untyped code: #<syntax:stdin:: a>
in: the 1st argument of
a part of the or/c of
(or/c
struct-predicate-procedure?/c
(-> Any boolean?))
contract from: (interface for custom-set?)
blaming: (interface for custom-set?)
对 UNTYPED
模块的相同调用有效,并且 returns #f
符合预期。你能告诉我为什么语法对象会在这里破坏契约吗?我可以解决这个问题吗?
这是一个由语法对象契约不够好引起的错误。具体来说,syntax/c
合约适用于平面合约,而 Typed Racket 希望在涉及 Any
类型时使用伴侣合约。
这里涉及的Any
是由#:opaque
引入的隐式Any
需要谓词custom-set?
。它出现在输入中,保护以类型化代码开始并以非类型化代码结束的值。由于未类型化的代码可能会尝试与类型化的高阶值混淆,因此它必须用伴侣契约包装 any-wrap/c
(Typed Racket 内部)。
any-wrap/c
用于保护潜在的高阶值,以及可能包含高阶值的容器值。如果某些部分是可变的,或者如果某些部分中有函数,则不允许未类型化代码改变该数据或调用该函数。
语法对象是容器。它们可以在 "syntax-e" 和语法属性中包含任意值。理想情况下,Typed Racket 的 any-wrap/c
合约应该将语法对象包装在保护这些地方的伴侣合约中。不幸的是,合同系统中的 syntax/c
合同还不够好。由于这种语法对象被认为是 "unsafe" 容器,如果 any-wrap/c
不能安全地包装它们,它必须引发合同错误。
我认为这个问题在未来可能得到解决的唯一方法是改进 syntax/c
以与伴侣合同一起使用。之后 any-wrap/c
可以像列表一样考虑语法对象安全容器。