{-# LANGUAGE Safe #-}

-- | This module contains monadic predicates.

module Universum.Bool.Guard
       ( guardM
       , ifM
       , unlessM
       , whenM
       ) where

import Universum.Bool.Reexport (Bool, guard, unless, when)
import Universum.Function (flip)
import Universum.Monad (Monad, MonadPlus, (>>=))

-- $setup
-- >>> import Universum.Applicative (pure)
-- >>> import Universum.Bool.Reexport (Bool (..))
-- >>> import Universum.Function (($))
-- >>> import Universum.Monad (Maybe (..))
-- >>> import Universum.Print (putTextLn)

-- | Monadic version of 'when'.
--
-- >>> whenM (pure False) $ putTextLn "No text :("
-- >>> whenM (pure True)  $ putTextLn "Yes text :)"
-- Yes text :)
-- >>> whenM (Just True) (pure ())
-- Just ()
-- >>> whenM (Just False) (pure ())
-- Just ()
-- >>> whenM Nothing (pure ())
-- Nothing
whenM :: Monad m => m Bool -> m () -> m ()
whenM :: forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
whenM m Bool
p m ()
m = m Bool
p m Bool -> (Bool -> m ()) -> m ()
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Bool -> m () -> m ()) -> m () -> Bool -> m ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when m ()
m
{-# INLINE whenM #-}

-- | Monadic version of 'unless'.
--
-- >>> unlessM (pure False) $ putTextLn "No text :("
-- No text :(
-- >>> unlessM (pure True) $ putTextLn "Yes text :)"
unlessM :: Monad m => m Bool -> m () -> m ()
unlessM :: forall (m :: * -> *). Monad m => m Bool -> m () -> m ()
unlessM m Bool
p m ()
m = m Bool
p m Bool -> (Bool -> m ()) -> m ()
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= (Bool -> m () -> m ()) -> m () -> Bool -> m ()
forall a b c. (a -> b -> c) -> b -> a -> c
flip Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless m ()
m
{-# INLINE unlessM #-}

-- | Monadic version of @if-then-else@.
--
-- >>> ifM (pure True) (putTextLn "True text") (putTextLn "False text")
-- True text
ifM :: Monad m => m Bool -> m a -> m a -> m a
ifM :: forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifM m Bool
p m a
x m a
y = m Bool
p m Bool -> (Bool -> m a) -> m a
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Bool
b -> if Bool
b then m a
x else m a
y
{-# INLINE ifM #-}

-- | Monadic version of 'guard'. Occasionally useful.
-- Here some complex but real-life example:
--
-- @
-- findSomePath :: IO (Maybe FilePath)
--
-- somePath :: MaybeT IO FilePath
-- somePath = do
--     path <- MaybeT findSomePath
--     guardM $ liftIO $ doesDirectoryExist path
--     return path
-- @
guardM :: MonadPlus m => m Bool -> m ()
guardM :: forall (m :: * -> *). MonadPlus m => m Bool -> m ()
guardM m Bool
f = m Bool
f m Bool -> (Bool -> m ()) -> m ()
forall a b. m a -> (a -> m b) -> m b
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= Bool -> m ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard
{-# INLINE guardM #-}