I've written this so that I can terminate a monadic fold early:
myfoldM :: (Monad m) => (a -> b -> m (Maybe a)) -> a -> [b] -> m (Maybe a)
myfoldM _ a [] = return $ Just a
myfoldM f a (x:xs) = do ma <- f a x;
case ma of
Nothing -> return Nothing
Just a' -> myfoldM f a' xs
and I'm wondering if there is a more elegant way to express this or if something similar exists in a library. Of course there is an analogous version replacing Maybe
with Either
.
Update... here is a complete solution based on Petr Pudlák's answer:
import Control.Monad (foldM,Monad,mzero)
import Control.Monad.Trans.Maybe (MaybeT(..))
import Control.Monad.Trans.Class (lift)
myfoldM' :: (Monad m) => (a -> b -> MaybeT m a) -> a -> [b] -> m (Maybe a)
myfoldM' f = (runMaybeT .) . foldM f
go :: Int -> Int -> MaybeT IO Int
go s i = do
lift $ putStrLn $ "i = " ++ show i
if i <= 4 then return (s+i) else mzero
test n = do
myfoldM' go 0 [1..n] >>= print
-- test 3 => Just 6
-- test 5 => Nothing
This is just a standard monadic foldM
enhanced with early exit. This can be done just by wrapping the inner computation into MaybeT
:
import Control.Monad
import Control.Monad.Trans.Error
import Control.Monad.Trans.Maybe
myfoldM :: (Monad m) => (a -> b -> m (Maybe a)) -> a -> [b] -> m (Maybe a)
myfoldM f = (runMaybeT .) . foldM ((MaybeT .) . f)
But I'd say it's more convenient for the folding function to be given using MaybeT
directly, because then it can easily terminate the computation by mzero
, instead of manipulating Maybe
values, and in such a case it's almost not worth writing a separate function for it:
myfoldM' :: (Monad m) => (a -> b -> MaybeT m a) -> a -> [b] -> m (Maybe a)
myfoldM' f = (runMaybeT .) . foldM f
For Either
it's the same:
myfoldM'' :: (Monad m, Error e)
=> (a -> b -> ErrorT e m a) -> a -> [b] -> m (Either e a)
myfoldM'' f = (runErrorT .) . foldM f
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