{-# LANGUAGE CPP, NoImplicitPrelude #-} module Control.Monad.Compat ( module Base , Monad(..) , MonadPlus(..) #if !(MIN_VERSION_base(4,8,0)) , foldM , foldM_ , forM , forM_ , guard , mapM , mapM_ , msum , sequence , sequence_ , unless , when , (<$!>) #endif #if !(MIN_VERSION_base(4,9,0)) , forever , filterM , mapAndUnzipM , zipWithM , zipWithM_ , replicateM , replicateM_ #endif ) where #if MIN_VERSION_base(4,9,0) import Control.Monad as Base #else import Control.Monad as Base hiding ( forever , filterM , mapAndUnzipM , zipWithM , zipWithM_ , replicateM , replicateM_ # if !(MIN_VERSION_base(4,8,0)) , foldM , foldM_ , forM , forM_ , guard , mapM , mapM_ , msum , sequence , sequence_ , unless , when # endif ) import Control.Applicative import Data.Foldable.Compat import Data.Traversable import Prelude.Compat #endif #if !(MIN_VERSION_base(4,8,0)) -- | Conditional execution of 'Applicative' expressions. For example, -- -- > when debug (putStrLn "Debugging") -- -- will output the string @Debugging@ if the Boolean value @debug@ -- is 'True', and otherwise do nothing. when :: (Applicative f) => Bool -> f () -> f () {-# INLINEABLE when #-} {-# SPECIALISE when :: Bool -> IO () -> IO () #-} {-# SPECIALISE when :: Bool -> Maybe () -> Maybe () #-} when p s = if p then s else pure () -- | @'guard' b@ is @'pure' ()@ if @b@ is 'True', -- and 'empty' if @b@ is 'False'. guard :: (Alternative f) => Bool -> f () guard True = pure () guard False = empty -- | The reverse of 'when'. unless :: (Applicative f) => Bool -> f () -> f () {-# INLINEABLE unless #-} {-# SPECIALISE unless :: Bool -> IO () -> IO () #-} {-# SPECIALISE unless :: Bool -> Maybe () -> Maybe () #-} unless p s = if p then pure () else s {- | The 'foldM' function is analogous to 'foldl', except that its result is encapsulated in a monad. Note that 'foldM' works from left-to-right over the list arguments. This could be an issue where @('>>')@ and the `folded function' are not commutative. > foldM f a1 [x1, x2, ..., xm] == > do > a2 <- f a1 x1 > a3 <- f a2 x2 > ... > f am xm If right-to-left evaluation is required, the input list should be reversed. Note: 'foldM' is the same as 'foldlM' -} foldM :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b {-# INLINEABLE foldM #-} {-# SPECIALISE foldM :: (a -> b -> IO a) -> a -> [b] -> IO a #-} {-# SPECIALISE foldM :: (a -> b -> Maybe a) -> a -> [b] -> Maybe a #-} foldM = foldlM -- | Like 'foldM', but discards the result. foldM_ :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m () {-# INLINEABLE foldM_ #-} {-# SPECIALISE foldM_ :: (a -> b -> IO a) -> a -> [b] -> IO () #-} {-# SPECIALISE foldM_ :: (a -> b -> Maybe a) -> a -> [b] -> Maybe () #-} foldM_ f a xs = foldlM f a xs >> return () infixl 4 <$!> -- | Strict version of 'Data.Functor.<$>'. -- -- /Since: 4.8.0.0/ (<$!>) :: Monad m => (a -> b) -> m a -> m b {-# INLINE (<$!>) #-} f <$!> m = do x <- m let z = f x z `seq` return z #endif #if !(MIN_VERSION_base(4,9,0)) -- | @'forever' act@ repeats the action infinitely. forever :: (Applicative f) => f a -> f b {-# INLINE forever #-} forever a = let a' = a *> a' in a' -- Use explicit sharing here, as it is prevents a space leak regardless of -- optimizations. -- | This generalizes the list-based 'filter' function. {-# INLINE filterM #-} filterM :: (Applicative m) => (a -> m Bool) -> [a] -> m [a] filterM p = foldr (\ x -> liftA2 (\ flg -> if flg then (x:) else id) (p x)) (pure []) -- | The 'mapAndUnzipM' function maps its first argument over a list, returning -- the result as a pair of lists. This function is mainly used with complicated -- data structures or a state-transforming monad. mapAndUnzipM :: (Applicative m) => (a -> m (b,c)) -> [a] -> m ([b], [c]) {-# INLINE mapAndUnzipM #-} mapAndUnzipM f xs = unzip <$> traverse f xs -- | The 'zipWithM' function generalizes 'zipWith' to arbitrary applicative functors. zipWithM :: (Applicative m) => (a -> b -> m c) -> [a] -> [b] -> m [c] {-# INLINE zipWithM #-} zipWithM f xs ys = sequenceA (zipWith f xs ys) -- | 'zipWithM_' is the extension of 'zipWithM' which ignores the final result. zipWithM_ :: (Applicative m) => (a -> b -> m c) -> [a] -> [b] -> m () {-# INLINE zipWithM_ #-} zipWithM_ f xs ys = sequenceA_ (zipWith f xs ys) -- | @'replicateM' n act@ performs the action @n@ times, -- gathering the results. replicateM :: (Applicative m) => Int -> m a -> m [a] {-# INLINEABLE replicateM #-} {-# SPECIALISE replicateM :: Int -> IO a -> IO [a] #-} {-# SPECIALISE replicateM :: Int -> Maybe a -> Maybe [a] #-} replicateM cnt0 f = loop cnt0 where loop cnt | cnt <= 0 = pure [] | otherwise = liftA2 (:) f (loop (cnt - 1)) -- | Like 'replicateM', but discards the result. replicateM_ :: (Applicative m) => Int -> m a -> m () {-# INLINEABLE replicateM_ #-} {-# SPECIALISE replicateM_ :: Int -> IO a -> IO () #-} {-# SPECIALISE replicateM_ :: Int -> Maybe a -> Maybe () #-} replicateM_ cnt0 f = loop cnt0 where loop cnt | cnt <= 0 = pure () | otherwise = f *> loop (cnt - 1) #endif