{-# OPTIONS_GHC -Wall -fwarn-tabs #-} ---------------------------------------------------------------- -- ~ 2010.11.15 -- | -- Module : Control.Monad.Extras -- Copyright : Copyright (c) 2007--2010 wren ng thornton -- License : BSD3 -- Maintainer : wren@community.haskell.org -- Stability : experimental -- Portability : portable -- -- Some basic monad combinators that "Control.Monad" lacks. Many -- of these functions have been adopted by the @IfElse@ package: -- <http://hackage.haskell.org/cgi-bin/hackage-scripts/package/IfElse> ---------------------------------------------------------------- module Control.Monad.Extras ( -- * Monadic conditionals ifM, whenM, unlessM -- * Looping constructs , whileM, untilM -- * Specialized @return@s , return', returning -- * Other functions , liftM', maybeMP, maybeEither ) where import Control.Monad ---------------------------------------------------------------- -- | Choose a computation to run based on the boolean. ifM :: (Monad m) => m Bool -> m a -> m a -> m a {-# SPECIALIZE ifM :: IO Bool -> IO () -> IO () -> IO () #-} ifM mb mt mf = mb >>= \b -> if b then mt else mf {-# INLINE ifM #-} -- | If the boolean is true, then run the computation. whenM :: (Monad m) => m Bool -> m () -> m () {-# SPECIALIZE whenM :: IO Bool -> IO () -> IO () #-} whenM mb mt = mb >>= \b -> when b mt {-# INLINE whenM #-} -- | If the boolean is false, then run the computation. unlessM :: (Monad m) => m Bool -> m () -> m () {-# SPECIALIZE unlessM :: IO Bool -> IO () -> IO () #-} unlessM mb mf = mb >>= \b -> unless b mf {-# INLINE unlessM #-} -- | Execute a monadic action so long as a monadic boolean returns -- true. whileM :: (Monad m) => m Bool -> m () -> m () {-# SPECIALIZE whileM :: IO Bool -> IO () -> IO () #-} whileM mb m = do b <- mb ; when b (m >> whileM mb m) -- Cf. Prelude.until :: (a -> Bool) -> (a -> a) -> a -> a -- | Negation of 'whileM': execute an action so long as the boolean -- returns false. untilM :: (Monad m) => m Bool -> m () -> m () {-# SPECIALIZE untilM :: IO Bool -> IO () -> IO () #-} untilM mb m = do b <- mb ; unless b (m >> untilM mb m) -- | Strict version of 'return' because usually we don't need that -- extra thunk. return' :: (Monad m) => a -> m a return' x = return $! x {-# INLINE return' #-} -- | Take an action and make it into a side-effecting 'return'. -- Because I seem to keep running into @m ()@ and the like. -- -- This is the moral inverse of @Control.Monad.void :: Functor f -- => f a -> f ()@ which is added in @base-4.3.0.0@. returning :: (Monad m) => (a -> m b) -> (a -> m a) f `returning` x = f x >> return x {-# INLINE returning #-} infixr 8 `returning` -- For reference this is also helpful: -- > liftM2 (>>) f g == \x -> f x >> g x -- | This conversion is common enough to make a name for. maybeMP :: (MonadPlus m) => Maybe a -> m a {-# SPECIALIZE maybeMP :: Maybe a -> Maybe a #-} maybeMP Nothing = mzero maybeMP (Just x) = return x {-# INLINE maybeMP #-} -- | Strict version of 'liftM'. Useful, for example, to make 'foldM' -- strict which can be necessary to avoid stack overflows. liftM' :: (Monad m) => (a -> b) -> m a -> m b liftM' f mx = mx >>= (return $!) . f {-# INLINE liftM' #-} -- | A variant of 'maybe' (or 'either') for converting the Maybe -- monad into the (Either a) monad, i.e. for naming your errors. maybeEither :: a -> Maybe b -> Either a b maybeEither x Nothing = Left x maybeEither _ (Just y) = Right y {-# INLINE maybeEither #-} ---------------------------------------------------------------- ----------------------------------------------------------- fin.