{-# LANGUAGE Safe #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Protolude.Bool (
  whenM
, unlessM
, ifM
, guardM
, bool
, (&&^)
, (||^)
, (<&&>)
, (<||>)
) where

import Data.Bool (Bool(True, False), (&&), (||))
import Data.Function (flip)
import Control.Applicative(Applicative, liftA2)
import Control.Monad (Monad, MonadPlus, return, when, unless, guard, (>>=), (=<<))

bool :: a -> a -> Bool -> a
bool :: a -> a -> Bool -> a
bool a
f a
t Bool
p = if Bool
p then a
t else a
f

whenM :: Monad m => m Bool -> m () -> m ()
whenM :: m Bool -> m () -> m ()
whenM m Bool
p m ()
m =
  m Bool
p m Bool -> (Bool -> m ()) -> m ()
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

unlessM :: Monad m => m Bool -> m () -> m ()
unlessM :: m Bool -> m () -> m ()
unlessM m Bool
p m ()
m =
  m Bool
p m Bool -> (Bool -> m ()) -> m ()
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

ifM :: Monad m => m Bool -> m a -> m a -> m a
ifM :: 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 (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

guardM :: MonadPlus m => m Bool -> m ()
guardM :: m Bool -> m ()
guardM m Bool
f = Bool -> m ()
forall (f :: * -> *). Alternative f => Bool -> f ()
guard (Bool -> m ()) -> m Bool -> m ()
forall (m :: * -> *) a b. Monad m => (a -> m b) -> m a -> m b
=<< m Bool
f

-- | The '||' operator lifted to a monad. If the first
--   argument evaluates to 'True' the second argument will not
--   be evaluated.
infixr 2 ||^ -- same as (||)
(||^) :: Monad m => m Bool -> m Bool -> m Bool
||^ :: m Bool -> m Bool -> m Bool
(||^) m Bool
a m Bool
b = m Bool -> m Bool -> m Bool -> m Bool
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifM m Bool
a (Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
True) m Bool
b

infixr 2 <||>
-- | '||' lifted to an Applicative.
-- Unlike '||^' the operator is __not__ short-circuiting.
(<||>) :: Applicative a => a Bool -> a Bool -> a Bool
<||> :: a Bool -> a Bool -> a Bool
(<||>) = (Bool -> Bool -> Bool) -> a Bool -> a Bool -> a Bool
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 Bool -> Bool -> Bool
(||)
{-# INLINE (<||>) #-}

-- | The '&&' operator lifted to a monad. If the first
--   argument evaluates to 'False' the second argument will not
--   be evaluated.
infixr 3 &&^ -- same as (&&)
(&&^) :: Monad m => m Bool -> m Bool -> m Bool
&&^ :: m Bool -> m Bool -> m Bool
(&&^) m Bool
a m Bool
b = m Bool -> m Bool -> m Bool -> m Bool
forall (m :: * -> *) a. Monad m => m Bool -> m a -> m a -> m a
ifM m Bool
a m Bool
b (Bool -> m Bool
forall (m :: * -> *) a. Monad m => a -> m a
return Bool
False)

infixr 3 <&&>
-- | '&&' lifted to an Applicative.
-- Unlike '&&^' the operator is __not__ short-circuiting.
(<&&>) :: Applicative a => a Bool -> a Bool -> a Bool
<&&> :: a Bool -> a Bool -> a Bool
(<&&>) = (Bool -> Bool -> Bool) -> a Bool -> a Bool -> a Bool
forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 Bool -> Bool -> Bool
(&&)
{-# INLINE (<&&>) #-}