foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)Note that since the head of the resulting expression is produced by an application of the operator to the first element of the list, given an operator lazy in its right argument, foldr can produce a terminating expression from an unbounded list. For a general Foldable structure this should be semantically identical to,
foldr f z = foldr f z . toList
>>> foldr (||) False [False, True, False] True
>>> foldr (||) False [] False
>>> foldr (\c acc -> acc ++ [c]) "foo" ['a', 'b', 'c', 'd'] "foodcba"
>>> foldr (||) False (True : repeat False) TrueBut the following doesn't terminate:
>>> foldr (||) False (repeat False ++ [True]) * Hangs forever *
>>> take 5 $ foldr (\i acc -> i : fmap (+3) acc) [] (repeat 1) [1,4,7,10,13]
foldr f z [x1, x2, ..., xn] == x1 `f` (x2 `f` ... (xn `f` z)...)
>>> foldr1 (+) [1..4] 10
>>> foldr1 (+) [] Exception: Prelude.foldr1: empty list
>>> foldr1 (+) Nothing *** Exception: foldr1: empty structure
>>> foldr1 (-) [1..4] -2
>>> foldr1 (&&) [True, False, True, True] False
>>> foldr1 (||) [False, False, True, True] True
>>> foldr1 (+) [1..] * Hangs forever *
foldrM f z t = do yy <- f y z xx <- f x yy ... bb <- f b cc aa <- f a bb return aa -- Just @return z@ when the structure is emptyFor a Monad m, given two functions f1 :: a -> m b and f2 :: b -> m c, their Kleisli composition (f1 >=> f2) :: a -> m c is defined by:
(f1 >=> f2) a = f1 a >>= f2Another way of thinking about foldrM is that it amounts to an application to z of a Kleisli composition:
foldrM f z t = f y >=> f x >=> ... >=> f b >=> f a $ zThe monadic effects of foldrM are sequenced from right to left, and e.g. folds of infinite lists will diverge. If at some step the bind operator (>>=) short-circuits (as with, e.g., mzero in a MonadPlus), the evaluated effects will be from a tail of the element sequence. If you want to evaluate the monadic effects in left-to-right order, or perhaps be able to short-circuit after an initial sequence of elements, you'll need to use foldlM instead. If the monadic effects don't short-circuit, the outermost application of f is to the leftmost element a, so that, ignoring effects, the result looks like a right fold:
a `f` (b `f` (c `f` (... (x `f` (y `f` z))))).
>>> let f i acc = do { print i ; return $ i : acc } >>> foldrM f [] [0..3] 3 2 1 0 [0,1,2,3]
foldrMap1 f g (x1 :| [x2, ..., xn1, xn]) == x1 `g` (x2 `g` ... (xn1 `g` (f xn))...)Note that since the head of the resulting expression is produced by an application of g to the first element of the list, if g is lazy in its right argument, foldrMap1 can produce a terminating expression from an unbounded list. For a general Foldable1 structure this should be semantically identical to:
foldrMap1 f g = foldrMap1 f g . toNonEmpty
>>> foldr' (+) [1..4] -- Use foldl' instead! 10 >>> foldr' (&&) [True, False, True, True] -- Use foldr instead! False >>> foldr' (||) [False, False, True, True] -- Use foldr instead! True
>>> foldr1 (+) [1..4] 10 >>> foldr1 (+) [] *** Exception: Prelude.foldr1: empty list >>> foldr1 (-) [1..4] -2 >>> foldr1 (&&) [True, False, True, True] False >>> foldr1 (||) [False, False, True, True] True >>> force $ foldr1 (+) [1..] *** Exception: stack overflow
iterate f == unfoldr (\x -> Just (x, f x))In some cases, unfoldr can undo a foldr operation:
unfoldr f' (foldr f z xs) == xsif the following holds:
f' (f x y) = Just (x,y) f' z = Nothing
>>> take 1 (unfoldr (\x -> Just (x, undefined)) 'a') "a"
>>> unfoldr (\b -> if b == 0 then Nothing else Just (b, b-1)) 10 [10,9,8,7,6,5,4,3,2,1]
>>> take 10 $ unfoldr (\(x, y) -> Just (x, (y, x + y))) (0, 1) [0,1,1,2,3,5,8,13,21,54]
bifoldr f g z ≡ foldr (either f g) z . toEitherList
> bifoldr (+) (*) 3 (5, 7) 26 -- 5 + (7 * 3) > bifoldr (+) (*) 3 (7, 5) 22 -- 7 + (5 * 3) > bifoldr (+) (*) 3 (Right 5) 15 -- 5 * 3 > bifoldr (+) (*) 3 (Left 5) 8 -- 5 + 3
>>> bifoldr1 (+) (5, 7) 12
>>> bifoldr1 (+) (Right 7) 7
>>> bifoldr1 (+) (Left 5) 5
> bifoldr1 (+) (BiList [1, 2] [3, 4]) 10 -- 1 + (2 + (3 + 4))
>>> bifoldr1 (+) (BiList [1, 2] []) 3On empty structures, this function throws an exception:
>>> bifoldr1 (+) (BiList [] []) *** Exception: bifoldr1: empty structure ...