在haskell中反转列表

时间:2014-11-10 15:31:27

标签: haskell functional-programming

我正在尝试撤销列表。

以下是我的代码:

reverseList :: [Int] -> [Int]
reverseList [] = []
reverseList (x:xs) =  x:reverseList xs

最终发生的事情是我最终以相同的顺序返回列表。我甚至有一个如何扭转列表的解决方案,但我想知道我在这里做错了什么?我对haskell很新,所以我认为我应该专注于理解更多,然后我可以轻松解决更多问题。我知道有很多解决方案可以解决这个问题,但我需要更多的帮助来理解我在这段代码中做错了什么。

5 个答案:

答案 0 :(得分:39)

在Haskell中有几种方法可以解决这个问题。天真的方法是使用连接函数++

reverseList [] = []
reverseList (x:xs) = reverseList xs ++ [x]

然而,对于大型列表来说这将非常慢,因为Haskell列表实际上是单链表,因此为了附加元素,您必须遍历整个列表。另一种方法是跟上你在辅助函数中构建的列表:

reverseList = go []
    where
        go acc [] = acc
        go acc (x:xs) = go (x:acc) xs

但是,这实际上只是fold模式:

reverseList = foldl (\acc x -> x : acc) []

\acc x -> x : acc只是flip (:),因此可以写成

reverseList = foldl (flip (:)) []

然而,最简单的方法可能是在Prelude中使用reverse函数。

我想指出您的reverseList :: [Int] -> [Int]类型可以推广到:: [a] -> [a],您不会对列表中的元素做任何特殊处理,您只需要构建一个新列表和他们一起。

答案 1 :(得分:5)

您将列表分为头部和尾部,但随后以相同的顺序重新组合列表。以列表[1, 2, 3]为例:

在第一次通话中,x将为1xs将为[2, 3]。然后,您创建一个新列表,前面是x(so 1),后跟reverseList [2, 3]

答案 2 :(得分:3)

在Haskell中有几种方法可以解决此问题。这是一个使用cons和last / init的解决方案:

reverseList  [] = []
reverseList  xs = last xs : reverseList (init xs)

或使用折叠架:

reverseList xs = foldl (\x y -> y:x) [] xs 

答案 3 :(得分:0)

基本上是使用追加的天真的算法

revList [] = []
revList (x:xs) = revList xs ++ [x]

效率低下,因为附加是O(n)操作,其中n++运算符的第一个(左)参数的长度。因此,上面的revList函数结果为O(n(n-1)/ 2)〜O(n ^ 2)。

因此,对于此类附加繁重的任务,存在差异列表数据类型。

差异列表只是表示为功能的列表。我的意思是,当以DList类型表示时,像[1,2,3]这样的列表将是\xs -> [1,2,3] ++ xs或简称为([1,2,3] ++)

type DList a = [a] -> [a]

toDList :: [a] -> DList a
toDList xs  = (xs ++ )

fromDList :: DList a -> [a]
fromDList f = f []

这很酷,因为因为DList是函数,所以我们可以通过composition(。)运算符将它们附加并获得新的DList。换句话说,toDList (xs ++ ys) == (toDList xs) . (toDList ys)

那么这有什么用?通过使用嵌套的函数组合,我们可以以类似于revList函数的方式来反转列表,但这将使我们花费更少。因为每个函数的组成都是O(1),所以只有O(n)。

revList' :: [a] -> DList a
revList' []     = toDList []
revList' (x:xs) = revList' xs . toDList [x]

现在我们将[a]中的DList a颠倒了,我们需要应用fromDList

fastReverse :: [a] -> [a]
fastReverse = fromDList . revList'

差异列表数据类型不像我上面显示的那么简单。它可以具有Monoid,Functor和MonadT实例。有关此有用数据类型的更多信息,请检查Data.DList

答案 4 :(得分:0)

简单;使用内置的reverse函数:

print (reverse [1,2,3,4,5]) -- [5,4,3,2,1]