此错误消息中代表[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]
答案 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]
带有额外的类约束(这些约束无可置疑)。