[英]terminating a monadic fold early
我写了这篇文章,以便我可以提前终止monadic折叠:
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
我想知道是否有一种更优雅的方式来表达这一点,或者如果库中存在类似的东西。 当然有一个类似的版本取代了Maybe
with Either
。
更新......这是基于PetrPudlák答案的完整解决方案:
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
这只是一个标准的foldM
,提前退出。 这可以通过将内部计算包装到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)
但是我会说使用MaybeT
直接给出折叠函数更方便,因为它可以很容易地通过mzero
终止计算,而不是操纵Maybe
值,在这种情况下,几乎不值得编写单独的函数它:
myfoldM' :: (Monad m) => (a -> b -> MaybeT m a) -> a -> [b] -> m (Maybe a)
myfoldM' f = (runMaybeT .) . foldM f
对于Either
它是相同的:
myfoldM'' :: (Monad m, Error e)
=> (a -> b -> ErrorT e m a) -> a -> [b] -> m (Either e a)
myfoldM'' f = (runErrorT .) . foldM f
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.