{-# LANGUAGE CPP #-}
-- |
-- Module: Language.KURE.Combinators.Monad
-- Copyright: (c) 2012--2021 The University of Kansas
-- License: BSD3
--
-- Maintainer: Neil Sculthorpe <neil.sculthorpe@ntu.ac.uk>
-- Stability: beta
-- Portability: ghc
--
-- This module provides conditional monadic combinators.

module Language.KURE.Combinators.Monad
           ( -- * Monadic Conditionals
             guardMsg
           , guardM
           , guardMsgM
           , ifM
           , whenM
           , unlessM
) where

import Control.Monad (unless)

#if !MIN_VERSION_base(4,13,0)
import Control.Monad.Fail(MonadFail)
#endif

------------------------------------------------------------------------------------------

-- | Similar to 'guard', but invokes 'fail' rather than 'mzero'.
guardMsg ::  MonadFail m => Bool -> String -> m ()
guardMsg :: Bool -> String -> m ()
guardMsg Bool
b String
msg = Bool -> m () -> m ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
unless Bool
b (String -> m ()
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
msg)
{-# INLINE guardMsg #-}

-- | As 'guardMsg', but with a default error message.
guardM ::  MonadFail m => Bool -> m ()
guardM :: Bool -> m ()
guardM Bool
b = Bool -> String -> m ()
forall (m :: * -> *). MonadFail m => Bool -> String -> m ()
guardMsg Bool
b String
"guardM failed"
{-# INLINE guardM #-}

-- | As 'guardMsg', but with an @m Bool@ as argument.
guardMsgM :: MonadFail m => m Bool -> String -> m ()
guardMsgM :: m Bool -> String -> m ()
guardMsgM m Bool
mb String
msg = do Bool
b <- m Bool
mb
                      Bool -> String -> m ()
forall (m :: * -> *). MonadFail m => Bool -> String -> m ()
guardMsg Bool
b String
msg
{-# INLINE guardMsgM #-}

-- | if-then-else lifted over a monadic predicate.
ifM ::  Monad m => m Bool -> m a -> m a -> m a
ifM :: m Bool -> m a -> m a -> m a
ifM m Bool
mb m a
m1 m a
m2 = do Bool
b <- m Bool
mb
                  if Bool
b then m a
m1 else m a
m2
{-# INLINE ifM #-}

-- | If the monadic predicate holds then perform the monadic action, else fail.
whenM ::  MonadFail m => m Bool -> m a -> m a
whenM :: m Bool -> m a -> m a
whenM m Bool
mb m a
ma = m Bool -> m a -> m a -> m a
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifM m Bool
mb m a
ma (String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"whenM: condition False")
{-# INLINE whenM #-}

-- | If the monadic predicate holds then fail, else perform the monadic action.
unlessM ::  MonadFail m => m Bool -> m a -> m a
unlessM :: m Bool -> m a -> m a
unlessM m Bool
mb m a
ma = m Bool -> m a -> m a -> m a
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifM m Bool
mb (String -> m a
forall (m :: * -> *) a. MonadFail m => String -> m a
fail String
"unlessM: condition True") m a
ma
{-# INLINE unlessM #-}

------------------------------------------------------------------------------------------