Does Haskell have foldlM'?

2019-06-16 17:26发布

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.

1条回答
倾城 Initia
2楼-- · 2019-06-16 17:49

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.

查看更多
登录 后发表回答