在我的 Typed Racket 程序中,我看到此错误:
any-wrap/c: contract violation
expected: acyclic value
given: #0=(foo #0#)
argument position: 1st
other arguments...:
什么可能导致此错误?
此错误很难诊断,因为通常根本不清楚
any-wrap/c
与发出错误信号的代码有什么关系。
这里的问题与 Typed Racket 中处理
casts
的方式有关。具体来说,以类型 Any
传递的值(最常见的是将类型化 Racket 值传递给非类型化 Racket 的结果)可以获取合约包装器 any-value/c
。如果该值是循环的(即该值内存在引用循环),则 any-wrap/c
合约可能会失败。这是一个例子。这段代码实际上直接使用了 Any
类型,而不是将值传递给无类型的 Racket。
#lang typed/racket
(require typed/rackunit)
(struct foo ([a : Any]) #:transparent #:mutable)
;; create a cyclic 'foo' structure
(define (make-cyclic-structure)
(define my-foo (foo 13))
(set-foo-a! my-foo my-foo)
my-foo)
;; pass a foo as an Any, then cast it and extract the field:
(define (take-any [x : Any]) : Any
(define its-a-foo (cast x foo))
(foo-a its-a-foo))
;; this causes the problem:
(take-any (make-cyclic-structure))
;; but so does this:
(check-equal? (make-cyclic-structure) 1234)
在这种情况下,对于两个有问题的行中的第一行有许多修复。最简单的就是将输入的类型从
take-any
更改为 Any
。另一种是将foo
改为(cast x foo)
;事实证明,使用 (assert x foo?)
可能会导致值不以相同的方式包装。你也可以使用类似的东西assert
...这有点笨重,但可以完成工作。
修复第二个(在测试用例中使用)可以通过以下方式完成
(match x
[(foo a) x])
...这不太好(失败消息只是报告它想要 true 并且得到 false),但仍然执行正确的测试。