如何读取此孔错误

时间:2015-09-02 04:17:27

标签: haskell types functional-programming

我正在尝试编写flatMap的实现。但这是无关紧要的,我对理解错误信息非常感兴趣。但到目前为止,我有以下情况:

flatMap ::
(a -> List b)
  -> List a
  -> List b
flatMap f xs = foldRight undefined undefined _undefined

这为类型孔提供了以下错误:

Found hole ‘_undefined’ with type: List a0
    Where: ‘a0’ is an ambiguous type variable
    Relevant bindings include
      xs :: List a (bound at src/Course/List.hs:266:11)
      f :: a -> List b (bound at src/Course/List.hs:266:9)
      flatMap :: (a -> List b) -> List a -> List b
        (bound at src/Course/List.hs:266:1)
    In the third argument of ‘foldRight’, namely ‘_undefined’
    In the expression: foldRight undefined undefined _undefined
    In an equation for ‘flatMap’:
        flatMap f xs = foldRight undefined undefined _undefined

我知道这个洞的正确的挂钩是xs,但是我不明白为什么haskell编译器给它一个表示为List a0的类型以及它与I类型将如何使用List a?< / p>

我认为这与整体可以采用List a或类型的超集这一事实有关?那么为什么它只是称它为List b而不是具体列出a0。

干杯, 吉姆

1 个答案:

答案 0 :(得分:4)

粗略地说,编译器推断类型如下。

让每个undefined给出一个不同类型的未知:

flatMap :: (a -> List b) -> List a -> List b
flatMap f xs =
   foldRight (undefined :: a1) (undefined :: b1) (_undefined :: c1)

现在,foldRight期望二进制函数的类型为a2 -> b2 -> b2,因此请让a1更精确。

flatMap :: (a -> List b) -> List a -> List b
flatMap f xs =
   foldRight (undefined :: a2 -> b2 -> b2) (undefined :: b1) (_undefined :: c1)

现在,foldRight要求第二个undefined具有b1 ~ b2类型,而最后一个必须具有c1 ~ List a2类型。

flatMap :: (a -> List b) -> List a -> List b
flatMap f xs =
   foldRight (undefined :: a2 -> b2 -> b2) (undefined :: b2) (_undefined :: List a2)

(假设我们有NilCons作为List类型的构造函数)

foldRight的结果是b2,但类型签名表明这实际上是List b。因此,

flatMap :: (a -> List b) -> List a -> List b
flatMap f xs =
   foldRight (undefined :: a2 -> List b -> List b) (undefined :: List b)
             (_undefined :: List a2)

现在我们完成了。请注意,没有约束可以允许我们推导出a2 ~ a,因此a2仍然是未知的,并且编译器无法为其建议更精确的类型,并且您的洞会生成您发布的GHC消息

更具体地说,看看a2 ~ Int

这个专业化
flatMap :: (a -> List b) -> List a -> List b
flatMap f xs =
   foldRight (g :: Int -> List b -> List b) (Nil :: List b) (Cons 3 Nil :: List Int)
   where g :: Int -> List b -> List b
         g y ys = ys

即使我们选择a2 ~ Int而不是a2 ~ a,上述类型也会进行检查。因此编译器无法推断a2 ~ a,因为有更多类型未知a2的解决方案。