foldrfoldl| foldr | foldl |
|---|---|
| right fold | left fold |
| can deal with infinite lists | can only deal with finite lists |
| (lazy) | (strict) |
| needs more heap space | needs more stack space |
| can lead to stack overflows | |
| efficiently compiled as a loop | |
| slower | fast |
| initial value is used when one reaches the end of the list | initial value combined with the first element of the list |
| immediately returns if f does not demand the rest of the recursion | immediately calls itself with new parameters until it reaches the end of the list |
| order is kept | order is reverse |
type: Foldable t ⇒ (a → b → b) → b → t a → b | type: Foldable t ⇒ (b → a → b) → b → t a → b |
| Note the order in underlined function. | |
foldl' :: Foldable t ⇒ (b → a → b) → b → t a → bfoldl1 :: (a → a → a) → [a] → afoldl1' :: (a → a → a) → [a] → a foldr1 :: (a → a → a) → [a] → a| variants with single quote (“'”) as postfix | variants with one (“1”) as postfix |
|---|---|
foldl' , foldl1' | foldl1, foldl1' , foldr1 |
| stricter variant | no initial value as parameter |
| forces the evaluation of the initial parameter before making the recursive call | initial value is last and first element of the list, respectively |
main :: IO () main = print f1 f1 :: Integer f1 = foldr (sumIfNot 100000000) 0 [0..100000000] sumIfNot :: Integer -> Integer -> Integer -> Integer sumIfNot nUntil nA nB | nA == nUntil = nA | otherwise = nA + nB
5000000050000000
main :: IO () main = print f1 f1 :: Integer f1 = foldr (sumIfNot 100000000) 0 [0..] sumIfNot :: Integer -> Integer -> Integer -> Integer sumIfNot nUntil nA nB | nA == nUntil = nA | otherwise = nA + nB
5000000050000000
main :: IO () main = print f1 f1 :: Integer f1 = foldl (sumIfNot 100000000) 0 [0..100000000] sumIfNot :: Integer -> Integer -> Integer -> Integer sumIfNot nUntil nA nB | nA == nUntil = nA | otherwise = nA + nB
5000000050000000
main :: IO () main = print f1 f1 :: Integer f1 = foldl (sumIfNot 100000000) 0 [0..] sumIfNot :: Integer -> Integer -> Integer -> Integer sumIfNot nUntil nA nB | nA == nUntil = nA | otherwise = nA + nB
sumIfNot 100:main :: IO () main = print f1 f1 :: Integer f1 = foldl (sumIfNot 100) 0 [0..100000000] sumIfNot :: Integer -> Integer -> Integer -> Integer sumIfNot nUntil nA nB | nA == nUntil = nA | otherwise = nA + nB
5000000050000000
foldl, but forces the evaluation of the initial parameter before making the recursive call (stricter variant)Data.Listimport qualified Data.List as L main :: IO () main = print f1 f1 :: Integer f1 = L.foldl' (sumIfNot 100000000) 0 [0..100000000] sumIfNot :: Integer -> Integer -> Integer -> Integer sumIfNot nUntil nA nB | nA == nUntil = nA | otherwise = nA + nB
5000000050000000
import qualified Data.List as L main :: IO () main = print f1 f1 :: Integer f1 = L.foldl' (sumIfNot 100000000) 0 [0..] sumIfNot :: Integer -> Integer -> Integer -> Integer sumIfNot nUntil nA nB | nA == nUntil = nA | otherwise = nA + nB
sumIfNot 100:import qualified Data.List as L main :: IO () main = print f1 f1 :: Integer f1 = L.foldl' (sumIfNot 100) 0 [0..100000000] sumIfNot :: Integer -> Integer -> Integer -> Integer sumIfNot nUntil nA nB | nA == nUntil = nA | otherwise = nA + nB
5000000050000000
The implications regarding order of execution:
main :: IO () main = do print s print $ f1 s s = ['a'..'z'] f1 :: String -> String f1 s = foldr (:) [] s
"abcdefghijklmnopqrstuvwxyz" "abcdefghijklmnopqrstuvwxyz"
main :: IO () main = do print s print $ f1 s s = ['a'..'z'] f1 :: String -> String f1 s = foldl (flip (:)) [] s
"abcdefghijklmnopqrstuvwxyz" "zyxwvutsrqponmlkjihgfedcba"
[a] → b → [a] from b → [a] → [a], and would not compile because of type mismatch.import qualified Data.List as L main :: IO () main = do print s print $ f1 s s = ['a'..'z'] f1 :: String -> String f1 s = L.foldl' (flip (:)) [] s
"abcdefghijklmnopqrstuvwxyz" "zyxwvutsrqponmlkjihgfedcba"
-):import qualified Data.List as L main :: IO () main = do print lnNumbers1 print lnNumbers2 print $ f1 lnNumbers1 print $ f1 lnNumbers2 print $ f2 lnNumbers1 print $ f2 lnNumbers2 print $ f3 lnNumbers1 print $ f3 lnNumbers2 lnNumbers1 = [31,7] lnNumbers2 = [31,7,3] f1 :: [Integer] -> Integer f1 ln = foldr (-) 0 ln f2 :: [Integer] -> Integer f2 ln = foldl (flip (-)) 0 ln f3 :: [Integer] -> Integer f3 ln = L.foldl' (flip (-)) 0 ln
[31,7] [31,7,3] 24 27 -24 27 -24 27
main :: IO () main = do print $ f1 lnNumbers1 print $ f1 lnNumbers2 print $ f1 lnNumbers3 lnNumbers1 = [31,13] lnNumbers2 = [31,13,3] lnNumbers3 = [1..100000000] f1 :: [Integer] -> Integer f1 ln = foldr (-) 0 ln
18 21 -50000000
foldl and reverse:import qualified Data.List as L main :: IO () main = do print $ f2 lnNumbers1 print $ f2 lnNumbers2 print $ f2 lnNumbers3 lnNumbers1 = [31,13] lnNumbers2 = [31,13,3] lnNumbers3 = [1..100000000] f2 :: [Integer] -> Integer f2 ln = foldlFlpRvrs (-) 0 ln foldlFlpRvrs :: (a -> b -> b) -> b -> [a] -> b foldlFlpRvrs f initial l = L.foldl' (flip f) initial (reverse l)
18 21 -50000000
L.foldl' or foldl is usedreverse functions are implementedfoldl, but….foldl1 foldl' , but…foldl1' foldr, but…foldr1