使用合约定义 Typed Racket 结构
Defining a Typed Racket structure with a contract
有没有一种方法可以在 Typed Racket 中为整个结构定义一个(类型化的)结构?在我的特殊情况下,我有一个将两个列表作为字段的结构,我希望这两个列表的长度相同。
我看过:
make-struct-type
,允许规范构造函数调用的 "guard"。如果长度不匹配,我可以通过一个引发异常的过程,但我不知道如何处理 make-struct-type
. 返回的值
struct/c
and the struct
form of contract-out
,它们都从各个领域的合同中产生结构合同。这在这里似乎没有帮助。
理想情况下,我想立即将合同绑定到结构(如 define/contract
),但我愿意在 provide
类型的过程时添加合同。但是,我目前单独提供识别器和访问器过程,而不是使用 struct-out
(这样我可以排除或重命名单个过程),我想保持这种灵活性。
现在我有这样的东西:
(provide
(rename-out
[MyStruct my-struct]
[MyStruct? my-struct?]
[MyStruct-foo my-struct-foo]
[MyStruct-bar my-struct-bar]
)
)
(struct MyStruct (
[foo : (Listof Symbol)]
[bar : (Listof Any)]
))
哇。我很惊讶在 Typed Racket 中做到这一点有多么困难。在普通(无类型)Racket 中,它就像添加 #:guard
一样简单,当你在 Typed Racket 中制作 struct
. Unfortunately, the struct
形式时不支持它。
因此,为了解决这个问题,我会生成一个具有私有(对于模块)构造函数名称的结构类型,然后创建您自己的构造函数,该函数实际上执行您希望它检查的契约。
最终看起来像这样:
(struct env ([keys : (Listof Symbol)]
[values : (Listof Any)])
#:constructor-name internal-env)
(: make-env (-> (Listof Symbol) (Listof Any) env))
(define (make-env k v)
(unless (= (length k) (length v))
(raise-arguments-error 'env
"env key and value counts don't match"
"keys" k
"values" v))
(internal-env k v))
现在,当您提供结构时,只需不提供 internal-env
,而是提供 make-env
函数:
(provide (except-out (struct-out env)
internal-env)
make-env)
现在,当我构造一个环境时,我得到一个(动态)检查以确保列表长度匹配:
> (make-env '() '())
#<env>
> (make-env '(a) '(1))
#<env>
> (make-env '(a) '())
env: env key and value counts don't match
keys: '(a)
values: '()
您可能会发现使用 Racket 中的保护函数定义和提供结构定义,然后 require/typed-ing 并在 Typed Racket 中对结构进行类型注释比尝试在 Typed Racket 中实现相同的效果更简单。
有没有一种方法可以在 Typed Racket 中为整个结构定义一个(类型化的)结构?在我的特殊情况下,我有一个将两个列表作为字段的结构,我希望这两个列表的长度相同。
我看过:
make-struct-type
,允许规范构造函数调用的 "guard"。如果长度不匹配,我可以通过一个引发异常的过程,但我不知道如何处理make-struct-type
. 返回的值
struct/c
and thestruct
form ofcontract-out
,它们都从各个领域的合同中产生结构合同。这在这里似乎没有帮助。
理想情况下,我想立即将合同绑定到结构(如 define/contract
),但我愿意在 provide
类型的过程时添加合同。但是,我目前单独提供识别器和访问器过程,而不是使用 struct-out
(这样我可以排除或重命名单个过程),我想保持这种灵活性。
现在我有这样的东西:
(provide
(rename-out
[MyStruct my-struct]
[MyStruct? my-struct?]
[MyStruct-foo my-struct-foo]
[MyStruct-bar my-struct-bar]
)
)
(struct MyStruct (
[foo : (Listof Symbol)]
[bar : (Listof Any)]
))
哇。我很惊讶在 Typed Racket 中做到这一点有多么困难。在普通(无类型)Racket 中,它就像添加 #:guard
一样简单,当你在 Typed Racket 中制作 struct
. Unfortunately, the struct
形式时不支持它。
因此,为了解决这个问题,我会生成一个具有私有(对于模块)构造函数名称的结构类型,然后创建您自己的构造函数,该函数实际上执行您希望它检查的契约。
最终看起来像这样:
(struct env ([keys : (Listof Symbol)]
[values : (Listof Any)])
#:constructor-name internal-env)
(: make-env (-> (Listof Symbol) (Listof Any) env))
(define (make-env k v)
(unless (= (length k) (length v))
(raise-arguments-error 'env
"env key and value counts don't match"
"keys" k
"values" v))
(internal-env k v))
现在,当您提供结构时,只需不提供 internal-env
,而是提供 make-env
函数:
(provide (except-out (struct-out env)
internal-env)
make-env)
现在,当我构造一个环境时,我得到一个(动态)检查以确保列表长度匹配:
> (make-env '() '())
#<env>
> (make-env '(a) '(1))
#<env>
> (make-env '(a) '())
env: env key and value counts don't match
keys: '(a)
values: '()
您可能会发现使用 Racket 中的保护函数定义和提供结构定义,然后 require/typed-ing 并在 Typed Racket 中对结构进行类型注释比尝试在 Typed Racket 中实现相同的效果更简单。