2017-09-02 62 views
1

我知道如何使用递归来逆转列表,但我正在尝试使用foldl来使其更有效。我的代码如下:未能使用foldl来逆转Haskell中的列表

reverse list = foldl (++) [] (map (\x -> [x]) list) 

当在GHCi中运行它时,它将返回与输入相同的列表。出了什么问题?我也试着用foldr来完成它,但它没有显示任何改变。

+0

见https://stackoverflow.com/questions/26847192/reverse-a-list-in-haskell – icc97

+0

的[反在Haskell列表]可能的复制(HTTPS ://sackoverflow.com/questions/26847192/reverse-a-list-in-haskell) – icc97

+0

@ icc97虽然在这个问题中给出了正确的'foldl'解决方案,但问题本身并不是真的,所以我不会说它是重复的。 – leftaroundabout

回答

3

foldl将累加器作为第一个参数传递给该函数。 ++将第一个参数连接到第二个参数,但是,要反转列表,需要将第二个参数连接到第一个参数。您可以使用flip (++)做到这一点:

Prelude> let reverse list = foldl (flip (++)) [] (map (\x -> [x]) list) 
Prelude> reverse [1..5] 
[5,4,3,2,1] 
+0

“连接...到”是非定向的;混乱。 “之前”会好很多。 –

3

取代先转换列表中的所有元素独居列表(这是昂贵的为好),你可以使用利弊(:)功能:

reverse :: Foldable t => t a -> [a] 
reverse = foldl (flip (:)) [] 

所以这里我们使用flip (:) :: [a] -> a -> [a]作为折叠函数。它需要一个尾部[a]和一个头部a,并构建一个头部作为第一个元素和尾部作为最后一个元素的列表。

那么什么情况是:

foldl (flip (:)) [] [1,4,2,5] 
-> foldl (flip (:)) (1:[]) [4,2,5] 
-> foldl (flip (:)) (4:1:[]) [2,5] 
-> foldl (flip (:)) (2:4:1:[]) [5] 
-> foldl (flip (:)) (5:2:4:1:[]) [] 
-> (5:2:4:1:[]) 
-> [5,2,4,1] 
+0

我一直在与foldl vs foldr争执不休,为什么要在这里使用foldl?你会介意一个快速的解释吗?谢谢! – Netwave

+0

@DanielSanchez:'foldr'开始列表的右端(或更一般的可折叠)。所以如果列表是'[a,b,c,d]',它会计算出'f a(f b(f c(f d z)))''。 'foldl'将计算f(f(f(f z a)b)c)d'。用'z'作为初始元素。 –

+0

好吧,我现在好多了,谢谢! – Netwave