我试图使用foldr重写Data.List.group,这是我的代码:
group' :: (Eq a) => [a] -> [[a]]
group' xs = foldr pack' [[head xs]] (tail xs)
where
pack' x acc = if x == (head $ head acc)
then x:(head acc)
else [x]:acc
现在我收到了这些错误:
Occurs check: cannot construct the infinite type: t0 = [t0]
In the expression: x
In the first argument of `(:)', namely `[x]'
In the expression: [x] : acc
和
Occurs check: cannot construct the infinite type: t0 = [t0]
Expected type: [[t0]]
Actual type: [[[t0]]]
In the second argument of `(:)', namely `acc'
In the expression: [x] : acc
In the expression:
if x == (head $ head acc) then x : (head acc) else [x] : acc
两者都是指最后一行。
我很确定我错过了一些东西,但是我从来没有真正意识到自从包装的类型以来所做的一切。应该是:
pack` a -> [[a]] -> [[a]]
答案 0 :(得分:2)
这一行:
then x:(head acc)
这一个
else [x]:acc
应该具有相同的类型。但是每个人都在列表的头部使用不同的类型。当它说“无法构造无限类型:t0 = [t0]”时,这意味着什么。如果a
= [a]
,那么它必须是无限维列表。
答案 1 :(得分:1)
这是一个评论,它已经由chi提出,但也许它有助于实际显示:执行此类功能的“正确”方法是head
和tail
,可以用模式匹配代替。此外,if
通常更好地重写为警卫。
group' :: (Eq a) => [a] -> [[a]]
group' (x0:xi) = foldr pack' [[x0]] xi
where
pack' xn acc@((x:xs):xss)
| xn == x = (xn : x : xs) : xss
| otherwise = [x]:acc
启用警告后,编译器会(正如它应该!)现在大声说你没有为空列表定义。所以你添加
group' [] = []
在pack'
内,我们确实不会发生空案例。