Haskell-将列表分为几个列表

时间:2019-01-10 14:53:34

标签: list haskell fold

给出一个已排序的元组列表,返回一个包含元组列表的列表,其中每个元组列表都符合条件:

1)对于元组列表中的每个(a,b)和(c,d),a == c

2)每个元组的第二个元素必须是前一个+1,因此对于[(a,y1),(b,y2),(c,y3)] => y2 = y1 + 1; y3 = y2 +1

示例:

输入

  

ex = [(0,2),(1,0),(1,2),(1,3),(1,4),(2,4)]

输出

  

groupTogether ex = [[(0,2)],[(1,0)],[(1,2),(1,3),(1,4)],[(2,4)] ]

这必须使用折叠来实现。

我的实现:

groupTogether :: [(Integer,Integer)]-> [[(Integer,Integer)]]
groupTogether [] = []
groupTogether pairs@(x:xs) = foldr (\(a,b) acc -> if ( (a == fst(last(last(acc)))) && (b == fst(last(last(acc)))) ) 
                                                  then (a,b) : (last(last(acc))) 
                                                  else [(a,b)] : ((last(acc)))
                                   ) [[]] pairs

我得到的错误:

enter image description here

2 个答案:

答案 0 :(得分:3)

[(a,b)] : last acc

我们有:

     acc :: [[(Integer, Integer)]] -- presumed
last acc ::  [(Integer, Integer)]
[(a,b)]  ::  [(Integer, Integer)]

因此,[(a,b)]具有正确的类型作为[[(Integer, Integer)]]的第一个元素,但是last acc没有正确的类型作为[[(Integer, Integer)]]的尾部。

(a,b) : last (last acc)

我们有:

           acc  :: [[(Integer, Integer)]] -- presumed
      last acc  ::  [(Integer, Integer)]
last (last acc) ::   (Integer, Integer)
(a,b)           ::   (Integer, Integer)

因此,(a,b)没有正确的类型成为[[(Integer, Integer)]]的第一个元素,而last (last acc)没有正确的类型成为{{1}的尾部}。

我将解决方法留给您;希望这足以阐明错误的含义,以便您可以取得进步。

答案 1 :(得分:3)

请注意,使用foldr时,将首先处理给定列表的右侧元素。例如,列表:

[(0,2),(1,0),(1,2),(1,3),(1,4),(2,4)]

在处理第三个元素(1,2)时,处理后的元素即acc

acc = [[(1,3),(1,4)],[(2,4)]]

因此,需要与(1,2)比较的元素是(1,3)。即head (head acc)而非last (last acc)。而且,除了使用head之外,还可以通过以下模式匹配来访问它:

(pairs@((x, y):xs):xss)

并与(a, b)进行比较:

a == x && b == (y - 1)

并在满足条件的情况下将它们分组在一起:

((a, b):pairs):xss

此外,定义阶跃函数而不是使用匿名函数更容易理解,因为它需要使用空白列表来处理最右边的元素,

step p [] = [[p]]

第一个元素一旦处理完毕,acc = [[p]]就不会在后续步骤中成为空列表,因此与上面定义的模式匹配。这是定义阶跃函数的方法:

groupTogether = foldr step []
    where step p [] = [[p]]
          step p@(a, b) acc@(pairs@((x, y):xs):xss) 
                | a == x && b == (y - 1) = (p:pairs):xss
                | otherwise              = [p]:acc

了解foldr的工作原理时,步进功能很简单。最后,作为补充说明,进行声明:

groupTogether [] = []

不是必需的。由于foldr在将空白列表传递给groupTogether时将返回其第二个参数,因此在此示例中,返回[]