foldl is tail recursive, so how come foldr runs faster than foldl?

后端 未结 7 1402
無奈伤痛
無奈伤痛 2020-11-27 10:42

I wanted to test foldl vs foldr. From what I\'ve seen you should use foldl over foldr when ever you can due to tail reccursion optimization.

This makes sense. Howeve

7条回答
  •  情话喂你
    2020-11-27 11:07

    The problem is that tail recursion optimization is a memory optimization, not a execution time optimization!

    Tail recursion optimization avoids the need to remember values for each recursive call.

    So, foldl is in fact "good" and foldr is "bad".

    For example, considering the definitions of foldr and foldl:

    foldl f z [] = z
    foldl f z (x:xs) = foldl f (z `f` x) xs
    
    foldr f z [] = z
    foldr f z (x:xs) = x `f` (foldr f z xs)
    

    That's how the expression "foldl (+) 0 [1,2,3]" is evaluated:

    foldl (+) 0 [1, 2, 3]
    foldl (+) (0+1) [2, 3]
    foldl (+) ((0+1)+2) [3]
    foldl (+) (((0+1)+2)+3) [ ]
    (((0+1)+2)+3)
    ((1+2)+3)
    (3+3)
    6
    

    Note that foldl doesn't remember the values 0, 1, 2..., but pass the whole expression (((0+1)+2)+3) as argument lazily and don't evaluates it until the last evaluation of foldl, where it reaches the base case and returns the value passed as the second parameter (z) wich isn't evaluated yet.

    On the other hand, that's how foldr works:

    foldr (+) 0 [1, 2, 3]
    1 + (foldr (+) 0 [2, 3])
    1 + (2 + (foldr (+) 0 [3]))
    1 + (2 + (3 + (foldr (+) 0 [])))
    1 + (2 + (3 + 0)))
    1 + (2 + 3)
    1 + 5
    6
    

    The important difference here is that where foldl evaluates the whole expression in the last call, avoiding the need to come back to reach remembered values, foldr no. foldr remember one integer for each call and performs a addition in each call.

    Is important to bear in mind that foldr and foldl are not always equivalents. For instance, try to compute this expressions in hugs:

    foldr (&&) True (False:(repeat True))
    
    foldl (&&) True (False:(repeat True))
    

    foldr and foldl are equivalent only under certain conditions described here

    (sorry for my bad english)

提交回复
热议问题