在简单的情况下解密Haskell类型的错误消息

时间:2013-11-30 16:40:51

标签: haskell

此错误消息中代表[t0] -> a0 -> [a1]的内容是什么?我刚才意识到我必须将(:)应用于foldr。为什么编译器不抱怨(*2)期望某种类型*作为参数?

Prelude> foldr (:) . (* 2) [] [1..10]

<interactive>:141:19:
    Couldn't match expected type `[t0] -> a0 -> [a1]'
                with actual type `[a2]'
    In the first argument of `* 2', namely `[]'
    In the second argument of `(.)', namely `(* 2) [] [1 .. 10]'
    In the expression: foldr (:) . (* 2) [] [1 .. 10]

2 个答案:

答案 0 :(得分:8)

所以foldr的类型是

 foldr :: (a -> b -> b) -> b -> [a] -> b

所以你传递它(:)所以它的类型变成了

 foldr (:) :: [a] -> [a] -> [a]

然而,您尝试使用(*2) [] [1..10]撰写它。这甚至没有很好的打字,所以你有麻烦。我认为你的问题是函数应用程序是所有函数的最高优先级。

  foldr ((:) . (*2)) [] [1..10]

明确的parens是必要的。

顺便说一下,你可以使用

 map (*2) [1..10]

答案 1 :(得分:3)

错误消息的说明

我们有

foldr (:) ::  [a] -> ([a] -> [a])
(.)       :: (c   -> d           ) -> (b -> c) -> (b -> d)

由此,我们得出结论

中的第二个参数y
foldr (:) . y

必须产生一个列表,即类型为

e -> [a]

在我们的案例中,y = (* 2) [] [1..10]。所以我们有:

(* 2) [] [1..10] :: e -> [a]  -- for some e and a

因此:

(* 2) [] :: [f] -> e -> [a]  -- for some e, a and f where (Num f, Enum f)

(对f的约束是因为我们在中使用数字文字和范围表示法 列出[1..10]。)现在,请考虑2(*)已超载,

(* 2) :: Num g => g -> g

从此我们得到[]必须与(* 2) []具有相同的类型(并且该类型必须是Num的实例):

[] :: [f] -> e -> [a]  -- for some e, a and f where
                       --   (Num f, Enum f, Num ([f] -> e -> [a]))

但事实并非如此,因为[]的某些[g]类型为g。现在让我们来看看 再次出现错误消息:

Couldn't match expected type `[t0] -> a0 -> [a1]'
            with actual type `[a2]'
In the first argument of `* 2', namely `[]'

因此模拟重命名类型变量,这正是错误消息所说的。

附录

错误指向`[]',所以看看typechecker认为应该在这个位置上做什么也许很有启发性。在GHC 7.8中,我们将能够使用TypeHoles扩展名,但是现在,一种简单的方法是从[]抽象,即用函数参数替换它:

Prelude> :t \ x -> foldr (:) . (* 2) x [1..10]
\ x -> foldr (:) . (* 2) x [1..10]
  :: (Enum t, Num ([t] -> a -> [a1]), Num t) =>
     ([t] -> a -> [a1]) -> a -> [a1] -> [a1]

通过这个,你可以很容易地看到这个词实际上仍然是类型正确的,它只是 要求x属于

类型
[t] -> a -> [a1]

带有额外的类约束(这些约束无可置疑)。