我正在尝试编写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。
干杯, 吉姆
答案 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)
(假设我们有Nil
和Cons
作为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
的解决方案。