2016-11-15 50 views
-1

非常基本的,但我发现这个问题令人沮丧。我想组列表连续元素:分组连续复制一个列表?

myList = [1,2,3,4,4,4,5] 

成为

myList = [[1],[2],[3],[4,4,4],[5]] 

这是用foldr用蓄电池我尝试:

print $ foldr (\ el acc -> if el /= head (head acc) then el ++ (head acc) else acc) [['a']] myList 

我不明白为什么我收到以下错误:

Couldn't match expected type ‘[a0]’ with actual type ‘Int’ 
In the expression: 'a' 
In the expression: ['a'] 
In the second argument of ‘foldr’, namely ‘[['a']]’ 

任何建议都会很棒!

+0

'EL ++头xs'具有输入'[α] '但累加器的类型为[[a]]'。你不能在'if'语句中返回不同的类型。 – ThreeFx

+0

你不知道['Data.List.group'](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-List.html#v:group)? – Jubobs

回答

2

在列表上写一个折叠需要我们回答两个例子:[](空列表或“nil”)和x:xs(元素后跟一个列表或“cons”)。

答案是什么时,列表是空的?可以说,答案也是一个空的列表。因此:

nilCase = [] 

列表不为空时的答案是什么?这取决于我们已经积累了什么。可以说我们已经积累了一个小组。我们知道这些组是非空的。

consCase x ((g11:_):gs) 

如果x == g11那么我们将它添加到组中。否则,我们开始一个新的小组。因此:

consCase x [email protected]([email protected](g11:_):gs) 
    | x == g11 = (x:g1):gs 
    | otherwise = [x]:ggs 

如果我们还没有积累任何组合,该怎么办?然后我们创建一个新组。

consCase x [] = [[x]] 

我们可以巩固的三种情况下,以2:

consCase x ggs 
    | [email protected](g11:_):gs <- ggs, x == g11 = (x:g1):gs 
    | otherwise      = [x]:ggs 

然后所需的折叠很简单:

foldr consCase nilCase 
1

使用foldr,它应该是:

group :: (Eq a) => [a] -> [[a]] 
group = foldr (\x acc -> if head acc == [] || head (head acc) == x then (x:head acc) : tail acc else [x] : acc) [[]] 
1

类型你的案件情况是[[Char]],你正试图建立[[Int]]类型的值。我们的基本情况应当是一个空列表,我们将在每个步骤中添加列表元素。

让我们来看看接下来写的匿名函数。请注意,由于累加器中当前的if类型,我们将失败(它们必须返回与累加器相同类型的值和相同类型的值)。如果模式匹配累加器,它会更好,更干净和不同的应用功能,在每种情况下:

func :: Eq a => [a] -> [[a]] 
func = foldr f [] 
    where f x []  = undefined 
     f x ([email protected](b1:_):bs) 
      | x == b1 = undefined 
      | otherwise = undefined 

当我们遇到的基本情况,我们应该加入我们的元素包裹在一个列表:

f x [] = [[x]] 

接下来,我们将处理非空列表,如果x等于列表头的下一个头部,我们应该把它加到那个列表中,否则我们就会

f x ([email protected](b1:_):bs) 
    | == b1 = (x:b):bs 
    | = [x]:b:bs 

把这个在一起,我们有:

func :: Eq a => [a] -> [[a]] 
func = foldr f [] 
    where f x []  = [[x]] 
     f x ([email protected](b1:_):bs) 
      | x == b1 = (x:b):bs 
      | otherwise = [x]:b:bs 

打碎了问题了,它更容易与lambda函数更紧凑重写这个。请注意,head[[]]只是[],所以我们可以将空列表大小写和相等大小写作为一个操作。因此,我们可以改写:

func :: (Eq a) => [a] -> [[a]] 
func = foldr (\x (b:bs) -> if b == [] || x == head b then (x:b):bs else [x]:b:bs) [[]] 

但是,这个方案最终需要,因为我们必须模式匹配累加器的所有版本中使用的head

+1

我认为第一个不太紧凑的版本更好。它更具可读性,不会用'(==)'测试一个空列表(这样做会不必要地带入一个'Eq'约束,尽管在这个特定的情况下你总是需要'Eq'),并且给出了' []'而不是'[[]]'为空列表,这是一个更自然的结果。在最后一点上:考虑到所有列表最终都会以空列表结束,可能会询问“[]”“组”对应哪个元素,或者“func xs”的最后一个元素是否应始终为[]。使用'[]'而不是'[[]]'作为初始累加器避免了这样的问题。 – duplode