Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does Haskell have foldlM'?

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.

like image 418
Jeff Burdges Avatar asked Jan 18 '12 23:01

Jeff Burdges


People also ask

What is a foldable in Haskell?

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.

How does Foldr work Haskell?

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.

What are monads Haskell?

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.


1 Answers

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 seqing 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.

like image 163
ehird Avatar answered Oct 05 '22 23:10

ehird