2016-11-15 49 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