如果我有这个插入功能:
insert x [] = [x]
insert x (h:t)
| x <= h = x:(h:t)
| otherwise = h:(insert x t)
这会产生一个排序列表:
foldr insert [] [1,19,-2,7,43]
但是这个:
foldr1 insert [1,19,-2,7,43]
生成'无法构造无限类型:a0 = [a0] '
我很困惑为什么第二个电话不起作用。
我已经查看了foldr和foldr1的定义,并且已经使用简单的算术函数进行了跟踪,但我仍然无法清楚地解释为什么第二次调用失败。
答案 0 :(得分:16)
让我们看看一些类型的签名。
foldr :: (a -> b -> b) -> b -> [a] -> b
foldr1 :: (a -> a -> a) -> [a] -> a
在这两种情况下,第一个参数都是两个参数的函数。
foldr1
,这两个参数必须具有相同的类型(结果也具有此类型)foldr
,这两个参数可能有不同的类型(结果与第二个参数的类型相同)您insert
的类型是什么?
答案 1 :(得分:9)
我喜欢这里给出的基于类型的答案,但我也想提供一个可操作的答案,解释为什么我们不希望这样做。让我们从foldr1
的来源开始:
foldr1 :: (a -> a -> a) -> [a] -> a
foldr1 _ [x] = x
foldr1 f (x:xs) = f x (foldr1 f xs)
现在,让我们尝试运行您的程序。
foldr1 insert [1,19,-2,7,43]
= { list syntax }
foldr1 insert (1:[19,-2,7,43])
= { definition of foldr1 }
insert 1 (foldr1 insert [19,-2,7,43])
= { three copies of the above two steps }
insert 1 (insert 19 (insert (-2) (insert 7 (foldr1 insert [43]))))
= { definition of foldr1 }
insert 1 (insert 19 (insert (-2) (insert 7 43)))
...哎呦!那insert 7 43
永远不会起作用。 =)
答案 2 :(得分:3)
foldr1
的类型是(a -> a -> a) -> [a] -> a
,即此函数的参数和结果具有相同的类型。但是,insert
的类型为Ord a => a -> [a] -> [a]
。对于foldr1 insert
输入良好的类型,a
和[a]
必须是同一类型。
但这意味着a == [a] == [[a]] == [[[a]]] == ...
,即a
是一种无限多列表。
答案 3 :(得分:1)
因为foldr1
正在尝试这样做:
insert 43 -7
会失败。
答案 4 :(得分:1)
问题在于:
foldr
会这样做:
insert 43 []
insert 7 result
这显然有效。
foldr1
会尝试执行以下操作:
insert 7 43
insert -2 result
这绝对是错误的。您可以看到,foldr1
要求操作的参数属于同一类型,而insert
则不是这样。