您可以检查递归调用结果的第一项是否具有相同的值。如果是这种情况,我们会在该列表前面加上x,否则我们会以x 作为列表的唯一成员开始一个“新组”,所以[x]:
breakList :: Eq a => [a] -> [[a]]
breakList [] = []
breakList [x] = [[x]] -- (1)
breakList (x:xs) -- (2)
| x == y = (x:ys) : yss -- (3)
| otherwise = [x] : ys : yss -- (4)
where ~(ys@(y:_):yss) = breakList xs -- (5)
这里我们首先计算尾递归的结果,我们知道这将是非空的,因为 (2) 中的 (x:xs) 模式只有在列表包含至少两个项目时才会触发(如果它只包含一项,则 (1) 子句将触发。
然后我们可以将结果与模式~(ys@(y:_):yss) 进行模式匹配,其中ys 是结果的第一个子列表,y 是该子列表的第一项,yss 是一个可能为空的列表已构建的其他组。
因此,我们可以检查我们必须放入组中的项目 x 是否与第一个子组的第一项 y 具有相同的值。如果是这种情况,我们使用(x:ys) : yss 构造一个新的 lsit,我们在第一个子列表前面加上x (2);如果不是这种情况,我们会在子列表前面加上 [x] 列表来创建一个新组。
我们可以让它更懒惰:
breakList :: Eq a => [a] -> [[a]]
breakList [] = []
breakList [x] = [[x]] -- (1)
breakList (x:xs@(y:_)) -- (2)
| x == y = (x:ys) : yss -- (3)
| otherwise = [x] : ys : yss -- (4)
where ~(ys:yss) = breakList xs -- (5)
这也可以在每次相同对象的无限列表上工作:breakList (1 : 1 : 2 : 4 : 5: 5 : repeat 1)) 将产生 [[1,1],[2],[4],[5,5],[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, …