racket - 类型化球拍中的自定义哈希集导致语法对象违反合同
问题描述
我有一套定制的套装,我想在打字球拍中使用它。我要求它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
哪种类型检查并返回#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
工作并返回。#f
你能告诉我为什么语法对象在这里违反合同吗?我可以解决这个问题吗?
解决方案
这是由于语法对象合同不够好而导致的错误。具体来说,syntax/c
合约适用于平面合约,而 Typed Racket 则希望在涉及类型时与伴侣合约一起使用Any
。
这里Any
涉及的是通过要求 predicateAny
引入的隐式。它出现在输入中,保护以类型代码开始并以非类型代码结束的值。由于无类型代码可能会尝试与有类型的高阶值混淆,因此必须用伴侣合同(Typed Racket 内部)包装它。#:opaque
custom-set?
any-wrap/c
用于保护潜在的any-wrap/c
高阶值以及可能包含高阶值的容器值。如果某个部分是可变的,或者如果某个部分中有一个函数,则不允许无类型代码改变该数据或调用该函数。
语法对象是容器。它们可以在“syntax-e”和语法属性中包含任意值。理想情况下,Typed Racket 的any-wrap/c
合约应该将语法对象包装在保护这些地方的伴侣合约中。不幸的是,syntax/c
合同系统中的合同还不够好。由于这种语法对象被认为是“不安全”的容器,如果any-wrap/c
不能安全地包装它们,它必须引发合约错误。
我认为未来可能会解决这个问题的唯一方法是改进syntax/c
与伴侣合同的合作。之后any-wrap/c
可以考虑语法对象安全容器,就像列表一样。
推荐阅读
- c# - 如何从 ASP.NET 核心导出 CSV 文件
- php - Laravel Passport 无法在 laravel 5.4 上安装。*
- python - 并行运行气流任务/dag
- java - 使用 Java Jersey api 对 REST api 的发布请求获取错误 405
- python - Anaconda3 Python 3.6 Pillow:无法导入 ImageCms
- javascript - 无法在猫鼬回调函数中设置变量
- python - 如何在python中创建一个整数平方列表?
- c - 如果我在分叉之前在进程上注册了自定义信号处理程序,后续子进程是否也会注册自定义信号处理程序?
- machine-learning - 使用带注释的文档创建注释任务
- bash - 如何使用 `$@` 将链式命令作为单个参数执行?