How can I write reverse by foldr efficiently in Haskell?

前端 未结 5 1491
误落风尘
误落风尘 2021-02-06 01:44

Note that the trivial solution

reverse a = foldr (\\b c -> c ++ [b] ) [] a

is not very efficient, because of the quadratic growth in complex

相关标签:
5条回答
  • 2021-02-06 02:20
    foldl (\acc x -> x:acc) [] [1,2,3]
    
    0 讨论(0)
  • 2021-02-06 02:33

    old question, I know, but is there anything non-optimal about this approach, it seems like foldr would be faster due to lazy evaluation and the code is fairly concise:

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

    is (++) significantly slower than (:), which requires a few logical twists as shown in FUZxxl's answer

    0 讨论(0)
  • 2021-02-06 02:38

    Basically, you need to transform 1:2:3:[] into (3:).(2:).(1:) and apply it to []. Thus:

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

    The meaning of the accumulated g here is that it acts on its argument by appending the reversed partial tail of xs to it.

    For the 1:2:3:[] example, in the last step x will be 3 and g will be (2:).(1:).

    0 讨论(0)
  • 2021-02-06 02:40

    Try this:

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

    Though it's usually really better to write it using foldl':

    reverse = foldl' (flip (:)) []
    
    0 讨论(0)
  • 2021-02-06 02:40

    Consider the following:

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

    Let's just "cut" it into pieces:

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

    Now we have this bunch of functions, let's compose them:

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

    ((.), id) it's Endo monoid, so

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

    For left fold we need just Dual monoid.

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

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

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

    Or simple:

    reverse' xs = (appEndo . foldr (flip mappend . Endo . (:)) mempty $ xs) []
    reverse' xs = (foldr (flip (.) . (:)) id $ xs) []
    reverse' = flip (foldr (flip (.) . (:)) id) []
    
    0 讨论(0)
提交回复
热议问题