List 是否将列表中的连续重复项分组?
非常基本,但我发现这个问题令人沮丧。我正在尝试对列表中的连续元素进行分组:List 是否将列表中的连续重复项分组?,list,haskell,List,Haskell,非常基本,但我发现这个问题令人沮丧。我正在尝试对列表中的连续元素进行分组: 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'
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']]’
任何建议都很好 使用
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) [[]]
案例的类型为
[[Char]]
,您正在尝试构建类型为[[Int]]]
的值。我们的基本情况应该是一个空列表,我们将在每个步骤中添加列表元素
让我们看看接下来编写的匿名函数。请注意,我们将失败,因为类型基于累加器中当前的if
(它们必须返回与累加器相同类型的值。如果我们对累加器进行模式匹配,并在每种情况下以不同的方式应用函数,则会更好、更干净:
func :: Eq a => [a] -> [[a]]
func = foldr f []
where f x [] = undefined
f x (b@(b1:_):bs)
| x == b1 = undefined
| otherwise = undefined
当我们遇到基本情况时,我们应该只添加包装在列表中的our元素:
f x [] = [[x]]
接下来,我们将处理非空列表。如果x等于列表头部的下一个头部,我们应该将其添加到该列表中。否则,我们应该
f x (b@(b1:_):bs)
| == b1 = (x:b):bs
| = [x]:b:bs
综上所述,我们有:
func :: Eq a => [a] -> [[a]]
func = foldr f []
where f x [] = [[x]]
f x (b@(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
,因为我们必须对累加器的所有版本进行模式匹配。编写折叠列表只需要回答两种情况:[]
(空列表,或“nil”)和x:xs
(元素后跟列表,或“cons”)
当列表为空时,答案是什么?假设答案也是一个空列表。因此:
nilCase = []
consCase x ggs@(g1@(g11:_):gs)
| x == g11 = (x:g1):gs
| otherwise = [x]:ggs
当列表不为空时,答案是什么?这取决于我们已经积累了什么。假设我们已经积累了一个组。我们知道组是非空的
consCase x ((g11:_):gs)
如果x==g11
,则我们将其添加到组中。否则,我们将开始一个新组。因此:
nilCase = []
consCase x ggs@(g1@(g11:_):gs)
| x == g11 = (x:g1):gs
| otherwise = [x]:ggs
如果我们还没有积累任何组呢?那么我们就创建一个新组
consCase x [] = [[x]]
我们可以将这三个案例合并为两个:
consCase x ggs
| g1@(g11:_):gs <- ggs, x == g11 = (x:g1):gs
| otherwise = [x]:ggs
el++head xs
的类型是[a]
,但累加器的类型是[[a]]
。如果语句是的话,你就不能返回不同的类型。你不知道吗?我认为第一个不太紧凑的版本更好。它更可读,不会用(==)测试空列表(这样做会带来一个不必要的Eq
约束,尽管在这种特定情况下,您无论如何都需要Eq
),并为空列表提供[]
而不是[[]]
,这是一个更自然的结果。在最后一点上:您可能会问哪个元素是[]
“组”如果所有列表最终都以空列表结束,则对应于func xs
的最后一个元素是否应始终为[]
。使用[]
而不是[[]]
作为初始累加器可避免此类问题。