How does one fold over a monad strictly? Data.Foldable
has the strict foldl'
and the monadic foldlM
, but no strict foldlM'
? Is the strictness somehow defined by the monad itself? If so, how does one work out what it is?
Imagine I must determine whether the product of an enormous list of ring elements is zero, but my ring isn't an integral domain, i.e. it contains zero devisors. In this case, I should tail recursively foldl
my multiplication ***
over the list, but return False
the moment the product becomes zero, rather than waiting on the full product.
safelist :: [p] -> Bool
safelist [] = True
safelist (x:xs) = snd $ foldl' f (x,True) xs
where f (u,b) v = (w, b && w /= Zero) where w = u *** v
I could perhaps simplify this code slightly using the Maybe
monad's foldlM
but doing so seemingly lacks the required strictness.
Advanced Haskell The Foldable type class provides a generalisation of list folding ( foldr and friends) and operations derived from it to arbitrary data structures. Besides being extremely useful, Foldable is a great example of how monoids can help formulating good abstractions.
To recap, with foldr , the purpose of the function argument is to take the first element of the list and the results of having folded the rest of the list, and return the new value. With foldl , the function argument takes a default value, the first element of the list, and returns a new default value.
A monad is an algebraic structure in category theory, and in Haskell it is used to describe computations as sequences of steps, and to handle side effects such as state and IO. Monads are abstract, and they have many useful concrete instances. Monads provide a way to structure a program.
There's no such standard function, but it's easy to define:
foldM' :: (Monad m) => (a -> b -> m a) -> a -> [b] -> m a
foldM' _ z [] = return z
foldM' f z (x:xs) = do
z' <- f z x
z' `seq` foldM' f z' xs
This is just the standard foldM
, but with the same seq
ing in it that foldl'
does (compared to foldl
). It's probably not defined anywhere standard because it's not likely to be all that useful: for most monads, (>>=)
is "strict" in the sense you need to use a left-fold without overflowing the stack; this is only useful when your excessive thunks are in the returned values themselves, but a useful application of foldM
will perform some monadic computation with the value from the last step, making that unlikely.
I think your code is simple enough as it is; I doubt foldM'
would make it any more elegant.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With