(: test (All (A) (-> A A (Rec Expr (Listof (U A Expr))) (Rec Expr (Listof (U A Expr))))))
(define (test new old expr)
(if (null? expr)
expr
(if (list? (car expr))
expr ; <- get error here
expr)))
得到错误
Type Checker: type mismatch
expected: (Rec g161252 (Listof (U A g161252)))
given: (Pairof
(U (Rec g161259 (Listof (U A g161259))) (Pairof Any (Listof Any)))
(Listof (U A (Rec g161268 (Listof (U A g161268)))))) in: expr
代码返回与输入代码完全相同的expr
。
(define (test new old expr)
(if (and (not (null? expr)) (list? (car expr)))
expr ; <- also get the error
expr))
但是
(define (test new old expr)
(if (and (list? (car expr)) (not (null? expr)))
expr ; <- this works fine
expr))
如果逻辑按此顺序排列,那么它可以正常工作。
那么为什么类型检查器会出现类型不匹配错误?
答案 0 :(得分:4)
问题是expr
“不够多态”。查询(list? (car expr))
将expr
的类型更改为与多态A
不兼容的内容。
(在我看来,您试图区分A
和嵌套Expr
,但是键入的球拍看到list?
并改进了A
的类型我想!)
这是另一个不具有多态性的函数。
(: id (All (A) (-> A A)))
(define (id x)
(if (boolean? x) x x))
<强>修复强>
如果您使用的是较旧版本的Racket(v6.2),您可以使用别名来解决此问题,但这不是一件好事。
(: id (All (A) (-> A A)))
(define (id x)
(define x2 x)
(if (boolean? x) x2 x)))
您可以使用list-ref
代替car
,因为list-ref
不允许谓词影响其参数。
...
(if (list? (list-ref expr 0))
expr
expr)))
稍微更改一下您的类型,因此可以明确地将A
与Expr
分开。
(: test (All (A) (-> A A (Rec Expr (Listof (U (Boxof A) Expr))) (Rec Expr (Listof (U (Boxof A) Expr))))))
(define (test new old expr)
(if (null? expr)
expr
(if (not (box? (car expr)))
expr
expr)))
停止使用Typed Racket的多态性 - 它太笨拙了!
订单问题是因为and
按顺序应用谓词,而这些谓词会破坏性地更改表达式的类型。因此,在您检查(not (null? expr))
之后测试(list? (car expr))
会忘记您曾进行过第一次检查。
以下是具有相同问题的更多代码。我们应该知道expr
是非null 并且有一个列表,但Typed Racket已被遗忘。
(: test2 (-> (Listof (U (List Natural) Boolean)) Boolean))
(define (test2 expr)
(if (and (list? (car expr)) (not (null? expr)))
(= 1 (car (car expr)))
#f))
这可能是一个错误。