如何在Haskell中有效地通过foldr写反向?

时间:2011-10-22 21:57:39

标签: haskell

请注意琐碎的解决方案

reverse a = foldr (\b c -> c ++ [b] ) [] a
由于复杂性的二次增长,

效率不高。如果试图使用通常的foldl进行折叠转换(盲目),但我的尝试

foldr (\b g x -> g ((\x old -> x:old) x b)) id list []

没有像我预期的那样工作。

5 个答案:

答案 0 :(得分:19)

试试这个:

reverse bs = foldr (\b g x -> g (b : x)) id bs []

虽然使用foldl'编写它通常会更好:

reverse = foldl' (flip (:)) []

答案 1 :(得分:8)

请考虑以下事项:

foldr (<>) seed [x1, x2, ... xn] == x1 <> (x2 <> (... <> (xn <> seed)))

让我们把它“剪切”成碎片:

(x1 <>) (x2 <>) ... (xn <>)  seed

现在我们有了这一系列功能,让我们来组合它们:

(x1 <>).(x2 <>). ... .(xn <>).id $ seed

((.), id)它是Endo monoid,所以

foldr (<>) seed xs == (appEndo . foldr (mappend.Endo.(<>)) mempty $ xs) seed

对于左侧折叠,我们只需要Dual monoid。

leftFold (<>) seed xs = (appEndo . getDual . foldr (mappend . Dual . Endo . (<>)) mempty $ xs) seed

(<>) = (:)seed = []

reverse' xs = (appEndo . getDual . foldr (mappend . Dual . Endo . (:)) mempty $ xs) []

或简单:

reverse' xs = (appEndo . foldr (flip mappend . Endo . (:)) mempty $ xs) []
reverse' xs = (foldr (flip (.) . (:)) id $ xs) []
reverse' = flip (foldr (flip (.) . (:)) id) []

答案 2 :(得分:2)

基本上,您需要将1:2:3:[]转换为(3 :)(2:)。(1 :)并将其应用于[]。因此:

reverse' xs = foldr (\x g -> g.(x:)) id xs []

这里积累的g的意思是它通过将xs的反转部分尾追加到它上来作用于它的参数。

对于1:2:3:[]示例,在最后一步中,x将为3,g将为(2:)。(1:)。

答案 3 :(得分:0)

foldl (\acc x -> x:acc) [] [1,2,3]

答案 4 :(得分:-2)

老问题,我知道,但是对于这种方法有什么不是最优的,看起来像折叠会因为懒惰的评估而变得更快而且代码相当简洁:

 reverse' :: [a] -> [a]
 reverse' = foldr (\x acc -> acc ++ [x]) []

是(++)明显慢于(:),这需要一些逻辑扭曲,如FUZxxl的回答所示