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