如果我有这个插入功能:
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 :: (a -> b -> b) -> b -> [a] -> b
foldr1 :: (a -> a -> a) -> [a] -> a
在这两种情况下,第一个参数都是两个参数的函数。
foldr1
,这两个参数必须具有相同的类型(并且结果也具有这种类型)foldr
,这两个参数可能具有不同的类型(并且结果与第二个参数具有相同的类型)你的类型是insert
什么?
我喜欢这里给出的基于类型的答案,但我也想给出一个可操作的答案来解释为什么我们不希望它进行类型检查。让我们从源代码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
永远行不通。=)
foldr1
is的类型(a -> a -> a) -> [a] -> a
,即该函数的参数和结果具有相同的类型。但是,insert
有类型Ord a => a -> [a] -> [a]
。用于foldr1 insert
良好的类型,a
并且[a]
必须是相同的类型。
但这意味着a == [a] == [[a]] == [[[a]]] == ...
,即,a
是一种无限多列表。
因为foldr1
正在尝试这样做:
insert 43 -7
这将失败。
问题如下:
foldr
会这样做:
insert 43 []
insert 7 result
这显然有效。
而foldr1
会尝试执行以下操作:
insert 7 43
insert -2 result
这绝对是错误的。您可以看到,foldr1
要求操作的参数是同一类型,而insert
.