1

我不是 Haskell 专业人士。今天我对今天的类型系统有一个有点奇怪的经历。第二行将导致类型错误。问题是maxdiag (as:bs:cs:ds)第二行的一点:

maxdiag ((a:as):(b:bs):(c:cs):(d:ds):xs) len =
  maximum [a*(bs !! 0)*(cs !! 1)*(ds !! 2), maxdiag (as:bs:cs:ds) (len-1)]

它失败并出现以下错误:

Occurs check: cannot construct the infinite type: a0 = [a0]
Expected type: [[a0]]
  Actual type: [a0]
In the second argument of `(:)', namely `ds'
In the second argument of `(:)', namely `cs : ds'

当我将第二行的违规部分更改为maxdiag (as:bs:cs:ds:xs), 使其显示为

maxdiag ((a:as):(b:bs):(c:cs):(d:ds):xs) len =
  maximum [a*(bs !! 0)*(cs !! 1)*(ds !! 2), maxdiag (as:bs:cs:ds:xs) (len-1)]

...那么就没有错误了。同样,如果我用它替换maxdiag (as:bs:cs:(ds:xs))它成功。我的问题是

  1. 这个错误是什么意思?
  2. 为什么会发生?
  3. 为什么这两个看似不同的东西可以解决它?
4

2 回答 2

9

要记住的是,它(:)具有 type a -> [a] -> [a],所以它的第一个参数是一个元素,而第二个参数是一个具有该元素类型的列表。如果元素本身是列​​表,则变为[a] -> [[a]] -> [[a]].

在您的示例中asbs,csdsall 都有 type [a], whilexs有 type [[a]],所以cs:ds是一个错误,而ds:xsis well-typed 。

该特定错误消息的原因是,当您尝试(:)在两个相同类型b的事物上使用时,唯一可行的方法是 ifb与 的类型相同[b],但这将是一个不允许的无限类型。

对于另一个问题,(:)运算符是右结合的,因此与andas:bs:cs:ds:xs相同。as:(bs:(cs:(ds:xs)))as:bs:cs:(ds:xs)

于 2012-05-06T18:32:06.503 回答
5

错误:

A.hs:2:63:
    Occurs check: cannot construct the infinite type: a0 = [a0]
    Expected type: [[a0]]
      Actual type: [a0]
    In the second argument of `(:)', namely `ds'
    In the second argument of `(:)', namely `cs : ds'

意味着您对类型有递归约束,这是非法的。即你的类型a必须是aand [a]

发生检查”是此时正在执行的类型检查算法部分的技术名称。“发生检查”可防止构造无限递归类型。

以我的经验,发生类似列表错误的检查失败意味着您混淆(:)(++). 那就是您有时将值用作列表元素,有时将其用作列表本身。

在这种情况下,它是(:)在表达式中的使用as:bs:cs:ds。可能您的意思是:

[as,bs,cs,ds]++xs

请注意,您的代码非常复杂 - 它对列表中元素的数量和形状做出了很多假设,而这些假设在任何时候都不太可能是正确的。我会非常害怕这段代码。这样做会更安全:

  • 使用模式匹配来排除其他情况(例如空列表、缺少元素)
  • 用模式匹配替换索引 (!!)。

并认真思考如何简化算法。

于 2012-05-06T18:34:33.610 回答