foldr package:protolude

Right-associative fold of a structure, lazy in the accumulator. In the case of lists, foldr, when applied to a binary operator, a starting value (typically the right-identity of the operator), and a list, reduces the list using the binary operator, from right to left:
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

Examples

Basic usage:
>>> foldr (||) False [False, True, False]
True
>>> foldr (||) False []
False
>>> foldr (\c acc -> acc ++ [c]) "foo" ['a', 'b', 'c', 'd']
"foodcba"
Infinite structures
⚠️ Applying foldr to infinite structures usually doesn't terminate. It may still terminate under one of the following conditions:
  • the folding function is short-circuiting
  • the folding function is lazy on its second argument
Short-circuiting
(||) short-circuits on True values, so the following terminates because there is a True value finitely far from the left side:
>>> foldr (||) False (True : repeat False)
True
But the following doesn't terminate:
>>> foldr (||) False (repeat False ++ [True])
* Hangs forever *
Laziness in the second argument
Applying foldr to infinite structures terminates when the operator is lazy in its second argument (the initial accumulator is never used in this case, and so could be left undefined, but [] is more clear):
>>> take 5 $ foldr (\i acc -> i : fmap (+3) acc) [] (repeat 1)
[1,4,7,10,13]
foldr' is a variant of foldr that performs strict reduction from right to left, i.e. starting with the right-most element. The input structure must be finite, otherwise foldr' runs out of space (diverges). If you want a strict right fold in constant space, you need a structure that supports faster than O(n) access to the right-most element, such as Seq from the containers package. This method does not run in constant space for structures such as lists that don't support efficient right-to-left iteration and so require O(n) space to perform right-to-left reduction. Use of this method with such a structure is a hint that the chosen structure may be a poor fit for the task at hand. If the order in which the elements are combined is not important, use foldl' instead.
Right-to-left monadic fold over the elements of a structure. Given a structure t with elements (a, b, c, ..., x, y), the result of a fold with an operator function f is equivalent to:
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 empty
For 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 >>= f2
Another 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 $ z
The 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))))).

Examples

Basic usage:
>>> let f i acc = do { print i ; return $ i : acc }

>>> foldrM f [] [0..3]
3
2
1
0
[0,1,2,3]
A variant of foldr that has no base case, and thus may only be applied to non-empty structures. This function is non-total and will raise a runtime exception if the structure happens to be empty.

Examples

Basic usage:
>>> 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 *
The unfoldr function is a `dual' to foldr: while foldr reduces a list to a summary value, unfoldr builds a list from a seed value. The function takes the element and returns Nothing if it is done producing the list or returns Just (a,b), in which case, a is a prepended to the list and b is used as the next element in a recursive call. For example,
iterate f == unfoldr (\x -> Just (x, f x))
In some cases, unfoldr can undo a foldr operation:
unfoldr f' (foldr f z xs) == xs
if the following holds:
f' (f x y) = Just (x,y)
f' z       = Nothing

Laziness

>>> take 1 (unfoldr (\x -> Just (x, undefined)) 'a')
"a"

Examples

>>> 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]