如何修复此类型球拍代码中的返回值?

时间:2015-11-02 10:34:32

标签: racket typed-racket

(: 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))

如果逻辑按此顺序排列,那么它可以正常工作。

那么为什么类型检查器会出现类型不匹配错误?

1 个答案:

答案 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))

<强>修复

  1. 如果您使用的是较旧版本的Racket(v6.2),您可以使用别名来解决此问题,但这不是一件好事。

    (: id (All (A) (-> A A)))
    (define (id x)
      (define x2 x)
      (if (boolean? x) x2 x)))
    
  2. 您可以使用list-ref代替car,因为list-ref不允许谓词影响其参数。

    ...
    (if (list? (list-ref expr 0))
      expr
      expr)))
    
  3. 稍微更改一下您的类型,因此可以明确地将AExpr分开。

    (: 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)))
    
  4. 停止使用Typed Racket的多态性 - 它太笨拙了!

  5. 订单问题是因为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))
    

    这可能是一个错误。