monad-loops-0.3: src/Control/Monad/Loops.hs
{-
- ``Control/Monad/Loops''
-}
{-# LANGUAGE
CPP
#-}
-- |A collection of loop operators for use in monads (mostly in stateful ones).
--
-- There is a general naming pattern for many of these:
-- Functions with names ending in _ discard the results of the loop body
-- as in the standard Prelude 'mapM' functions.
--
-- Functions with names ending in ' collect their results into 'MonadPlus'
-- containers. Note that any short-circuit effect that those types'
-- 'MonadPlus' instances may provide in a lazy context (such as the instance
-- for 'Maybe') will _not_ cause execution to short-circuit in these loops.
--
-- Functions with names ending in neither of those will generally return
-- just plain old lists.
module Control.Monad.Loops
( module Control.Monad.Loops
#ifdef useSTM
, module Control.Monad.Loops.STM
#endif
) where
import Control.Monad
import Control.Exception
import Control.Concurrent
#ifndef base4
#define SomeException Exception
#endif
#ifdef useSTM
import Control.Monad.Loops.STM
#endif
-- possibly-useful addition? :
-- concatMapM :: (Monad m, Traversable f, Monoid w) => (a -> m w) -> (f a) -> m w
-- would also like to implement an "interleavable" version of forkMapM (probably
-- using something other than a list in the return) that can effectively handle
-- very large or even infinite input lists.
-- |Like 'mapM', but run all the actions in parallel threads, collecting up
-- the results and returning them all. Does not return until all actions finish.
forkMapM :: (a -> IO b) -> [a] -> IO [Either SomeException b]
forkMapM f xs = do
mvars <- forM xs $ \x -> do
mvar <- newEmptyMVar
forkIO $ do
result <- handle (return . Left) $ do
y <- f x
return (Right y)
putMVar mvar result
return mvar
mapM takeMVar mvars
-- | like 'forkMapM' but without bothering to keep the return values
forkMapM_ :: (a -> IO b) -> [a] -> IO [Maybe SomeException]
forkMapM_ f xs = do
mvars <- forM xs $ \x -> do
mvar <- newEmptyMVar
forkIO $ do
-- in base >=4, need to nail down the type of 'handle'
let handleAny :: (SomeException -> IO a) -> IO a -> IO a
handleAny = handle
result <- handleAny (return . Just) $ do
f x
return Nothing
putMVar mvar result
return mvar
mapM takeMVar mvars
-- | like 'forkMapM_' but not even bothering to track success or failure
-- of the child threads. Still waits for them all though.
forkMapM__ :: (a -> IO b) -> [a] -> IO ()
forkMapM__ f xs = do
mvars <- forM xs $ \x -> do
mvar <- newEmptyMVar
forkIO $ do
-- in base >=4, need to nail down the type of 'handle'
let handleAny :: (SomeException -> IO a) -> IO a -> IO a
handleAny = handle
handleAny (\e -> return ()) $ do
f x
return ()
putMVar mvar ()
return mvar
mapM_ takeMVar mvars
{-# SPECIALIZE whileM :: IO Bool -> IO a -> IO [a] #-}
{-# SPECIALIZE whileM' :: Monad m => m Bool -> m a -> m [a] #-}
{-# SPECIALIZE whileM' :: IO Bool -> IO a -> IO [a] #-}
{-# SPECIALIZE whileM_ :: IO Bool -> IO a -> IO () #-}
-- |Execute an action repeatedly as long as the given boolean expression
-- returns True. The condition is evaluated before the loop body.
-- Collects the results into a list.
whileM :: Monad m => m Bool -> m a -> m [a]
whileM = whileM'
-- |Execute an action repeatedly as long as the given boolean expression
-- returns True. The condition is evaluated before the loop body.
-- Collects the results into an arbitrary 'MonadPlus' value.
whileM' :: (Monad m, MonadPlus f) => m Bool -> m a -> m (f a)
whileM' p f = do
x <- p
if x
then do
x <- f
xs <- whileM' p f
return (return x `mplus` xs)
else return mzero
-- |Execute an action repeatedly as long as the given boolean expression
-- returns True. The condition is evaluated before the loop body.
-- Discards results.
whileM_ :: (Monad m) => m Bool -> m a -> m ()
whileM_ p f = do
x <- p
if x
then do
f
whileM_ p f
else return ()
{-# SPECIALIZE untilM :: IO a -> IO Bool -> IO [a] #-}
{-# SPECIALIZE untilM' :: Monad m => m a -> m Bool -> m [a] #-}
{-# SPECIALIZE untilM' :: IO a -> IO Bool -> IO [a] #-}
{-# SPECIALIZE untilM_ :: IO a -> IO Bool -> IO () #-}
infixr 0 `untilM`
infixr 0 `untilM'`
infixr 0 `untilM_`
-- |Execute an action repeatedly until the condition expression returns True.
-- The condition is evaluated after the loop body. Collects results into a list.
-- Parameters are arranged for infix usage. eg. do {...} `untilM_` ...
untilM :: Monad m => m a -> m Bool -> m [a]
untilM = untilM'
-- |Execute an action repeatedly until the condition expression returns True.
-- The condition is evaluated after the loop body. Collects results into a
-- "MonadPlus" value.
-- Parameters are arranged for infix usage. eg. do {...} `untilM_` ...
untilM' :: (Monad m, MonadPlus f) => m a -> m Bool -> m (f a)
f `untilM'` p = do
x <- f
xs <- whileM' (liftM not p) f
return (return x `mplus` xs)
-- |Execute an action repeatedly until the condition expression returns True.
-- The condition is evaluated after the loop body. Discards results.
-- Parameters are arranged for infix usage. eg. do {...} `untilM_` ...
untilM_ :: (Monad m) => m a -> m Bool -> m ()
f `untilM_` p = f >> whileM_ (liftM not p) f
{-# SPECIALIZE whileJust :: IO (Maybe a) -> (a -> IO b) -> IO [b] #-}
{-# SPECIALIZE whileJust' :: Monad m => m (Maybe a) -> (a -> m b) -> m [b] #-}
{-# SPECIALIZE whileJust' :: IO (Maybe a) -> (a -> IO b) -> IO [b] #-}
{-# SPECIALIZE whileJust_ :: IO (Maybe a) -> (a -> IO b) -> IO () #-}
-- |As long as the supplied "Maybe" expression returns "Just _", the loop
-- body will be called and passed the value contained in the 'Just'. Results
-- are collected into a list.
whileJust :: Monad m => m (Maybe a) -> (a -> m b) -> m [b]
whileJust = whileJust'
-- |As long as the supplied "Maybe" expression returns "Just _", the loop
-- body will be called and passed the value contained in the 'Just'. Results
-- are collected into an arbitrary MonadPlus container.
whileJust' :: (Monad m, MonadPlus f) => m (Maybe a) -> (a -> m b) -> m (f b)
whileJust' p f = do
x <- p
case x of
Nothing -> return mzero
Just x -> do
x <- f x
xs <- whileJust' p f
return (return x `mplus` xs)
-- |As long as the supplied "Maybe" expression returns "Just _", the loop
-- body will be called and passed the value contained in the 'Just'. Results
-- are discarded.
whileJust_ :: (Monad m) => m (Maybe a) -> (a -> m b) -> m ()
whileJust_ p f = do
x <- p
case x of
Nothing -> return ()
Just x -> do
f x
whileJust_ p f
{-# SPECIALIZE unfoldM :: IO (Maybe a) -> IO [a] #-}
{-# SPECIALIZE unfoldM' :: (Monad m) => m (Maybe a) -> m [a] #-}
{-# SPECIALIZE unfoldM' :: IO (Maybe a) -> IO [a] #-}
{-# SPECIALIZE unfoldM_ :: IO (Maybe a) -> IO () #-}
-- |The supplied "Maybe" expression will be repeatedly called until it
-- returns 'Nothing'. All values returned are collected into a list.
unfoldM :: (Monad m) => m (Maybe a) -> m [a]
unfoldM = unfoldM'
-- |The supplied "Maybe" expression will be repeatedly called until it
-- returns 'Nothing'. All values returned are collected into an arbitrary
-- 'MonadPlus' thing.
unfoldM' :: (Monad m, MonadPlus f) => m (Maybe a) -> m (f a)
unfoldM' m = whileJust' m return
-- |The supplied "Maybe" expression will be repeatedly called until it
-- returns 'Nothing'. All values returned are discarded.
unfoldM_ :: (Monad m) => m (Maybe a) -> m ()
unfoldM_ m = whileJust_ m return
{-# SPECIALIZE unfoldrM :: (a -> IO (Maybe (b,a))) -> a -> IO [b] #-}
{-# SPECIALIZE unfoldrM' :: (Monad m) => (a -> m (Maybe (b,a))) -> a -> m [b] #-}
{-# SPECIALIZE unfoldrM' :: (a -> IO (Maybe (b,a))) -> a -> IO [b] #-}
-- |See 'Data.List.unfoldr'. This is a monad-friendly version of that.
unfoldrM :: (Monad m) => (a -> m (Maybe (b,a))) -> a -> m [b]
unfoldrM = unfoldrM'
-- |See 'Data.List.unfoldr'. This is a monad-friendly version of that, with a
-- twist. Rather than returning a list, it returns any MonadPlus type of your
-- choice.
unfoldrM' :: (Monad m, MonadPlus f) => (a -> m (Maybe (b,a))) -> a -> m (f b)
unfoldrM' f z = do
x <- f z
case x of
Nothing -> return mzero
Just (x, z) -> do
xs <- unfoldrM' f z
return (return x `mplus` xs)
{-# SPECIALIZE concatM :: [a -> IO a] -> (a -> IO a) #-}
-- |Compose a list of monadic actions into one action. Composes using
-- ('>=>') - that is, the output of each action is fed to the input of
-- the one after it in the list.
concatM :: (Monad m) => [a -> m a] -> (a -> m a)
concatM fs = foldr (>=>) return fs
{-# SPECIALIZE andM :: [IO Bool] -> IO Bool #-}
{-# SPECIALIZE orM :: [IO Bool] -> IO Bool #-}
-- |short-circuit 'and' for values of type Monad m => m Bool
andM :: (Monad m) => [m Bool] -> m Bool
andM [] = return True
andM (p:ps) = do
q <- p
if q
then andM ps
else return False
-- |short-circuit 'or' for values of type Monad m => m Bool
orM :: (Monad m) => [m Bool] -> m Bool
orM [] = return False
orM (p:ps) = do
q <- p
if q
then return True
else orM ps
{-# SPECIALIZE anyPM :: [a -> IO Bool] -> (a -> IO Bool) #-}
{-# SPECIALIZE allPM :: [a -> IO Bool] -> (a -> IO Bool) #-}
-- |short-circuit 'any' with a list of \"monadic predicates\". Tests the
-- value presented against each predicate in turn until one passes, then
-- returns True without any further processing. If none passes, returns False.
anyPM :: (Monad m) => [a -> m Bool] -> (a -> m Bool)
anyPM [] x = return False
anyPM (p:ps) x = do
q <- p x
if q
then return True
else anyPM ps x
-- |short-circuit 'all' with a list of \"monadic predicates\". Tests the value
-- presented against each predicate in turn until one fails, then returns False.
-- if none fail, returns True.
allPM :: (Monad m) => [a -> m Bool] -> (a -> m Bool)
allPM [] x = return True
allPM (p:ps) x = do
q <- p x
if q
then allPM ps x
else return False
{-# SPECIALIZE anyM :: (a -> IO Bool) -> [a] -> IO Bool #-}
{-# SPECIALIZE allM :: (a -> IO Bool) -> [a] -> IO Bool #-}
-- |short-circuit 'any' with a \"monadic predicate\".
anyM :: (Monad m) => (a -> m Bool) -> [a] -> m Bool
anyM p [] = return False
anyM p (x:xs) = do
q <- p x
if q
then return True
else anyM p xs
-- |short-circuit 'all' with a \"monadic predicate\".
allM :: (Monad m) => (a -> m Bool) -> [a] -> m Bool
allM p [] = return True
allM p (x:xs) = do
q <- p x
if q
then allM p xs
else return False
dropWhileM :: (Monad m) => (a -> m Bool) -> [a] -> m [a]
dropWhileM p [] = return []
dropWhileM p (x:xs) = do
q <- p x
if q
then dropWhileM p xs
else return xs
-- |like 'dropWhileM' but trims both ends of the list.
trimM :: (Monad m) => (a -> m Bool) -> [a] -> m [a]
trimM p xs = do
xs <- dropWhileM p xs
rxs <- dropWhileM p (reverse xs)
return (reverse rxs)
-- |return the first value from a list, if any, satisfying the given predicate.
firstM :: (Monad m) => (a -> m Bool) -> [a] -> m (Maybe a)
firstM p [] = return Nothing
firstM p (x:xs) = do
q <- p x
if q
then return (Just x)
else firstM p xs