使用合约定义Typed Racket结构

时间:2018-03-21 19:35:22

标签: racket typed-racket

有没有办法在(类型)结构旁边定义Typed Racket中整个结构的合约?在我的特定情况下,我有一个结构,它将两个列表作为字段,我想要求列表具有相同的长度。

我看过:

  • make-struct-type,它允许指定一个缓和构造函数调用的“guard”。如果长度不匹配,我可以传递引发异常的过程,但我不知道如何处理make-struct-type返回的值。
  • struct/cstruct形式的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)]
))

2 个答案:

答案 0 :(得分:2)

哇。我很惊讶在Typed Racket中做到这一点有多么困难。在普通(无类型)Racket中,它就像在struct中添加#:guard一样简单。不幸的是,Typed Racket中的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)

现在,当我构造一个env时,我得到(动态)检查以确保列表长度匹配:

> (make-env '() '())
#<env>
> (make-env '(a) '(1))
#<env>
> (make-env '(a) '())
env: env key and value counts don't match
  keys: '(a)
  values: '()

答案 1 :(得分:0)

您可能会发现从Racket定义并提供带有保护功能的结构定义,然后在Typed Racket中对结构进行需求/类型化和类型注释,这比单纯在Typed Racket中实现相同效果要简单得多。