{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE ScopedTypeVariables #-}

{- |
Module      : Primus.Bool
Description : boolean methods
Copyright   : (c) Grant Weyburne, 2022
License     : BSD-3
-}
module Primus.Bool (
  -- * builders
  boolMaybe,
  boolEither,
  boolThese,
  boolThese',

  -- * monadic functions
  boolM,
  unlessMB,
  whenMB,
) where

import Data.Bool
import Data.These

{- | monadic version of 'Data.Bool.bool'
 predicate appears first unlike 'Data.Bool.bool'
-}
boolM :: Monad m => m Bool -> m a -> m a -> m a
boolM :: m Bool -> m a -> m a -> m a
boolM m Bool
mb m a
mf m a
mt = m Bool
mb m Bool -> (Bool -> m a) -> m a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= m a -> m a -> Bool -> m a
forall a. a -> a -> Bool -> a
bool m a
mf m a
mt

{- | create a 'Maybe' using a predicate and a function for the success case
 predicate appears first unlike 'Data.Bool.bool'
-}
boolMaybe ::
  (a -> Bool) ->
  (a -> b) ->
  a ->
  Maybe b
boolMaybe :: (a -> Bool) -> (a -> b) -> a -> Maybe b
boolMaybe a -> Bool
p a -> b
r a
a
  | a -> Bool
p a
a = b -> Maybe b
forall a. a -> Maybe a
Just (a -> b
r a
a)
  | Bool
otherwise = Maybe b
forall a. Maybe a
Nothing

{- | create a 'Either' using a predicate and functions for the failure and success case
 predicates appear first unlike 'Data.Bool.bool'
-}
boolEither ::
  (a -> Bool) ->
  (a -> e) ->
  (a -> b) ->
  a ->
  Either e b
boolEither :: (a -> Bool) -> (a -> e) -> (a -> b) -> a -> Either e b
boolEither a -> Bool
p a -> e
l a -> b
r a
a
  | a -> Bool
p a
a = b -> Either e b
forall a b. b -> Either a b
Right (a -> b
r a
a)
  | Bool
otherwise = e -> Either e b
forall a b. a -> Either a b
Left (a -> e
l a
a)

{- | create a 'These' using two predicates and functions for the This case and That case
   False + *     == This (a -> e)
   True  + False == That (a -> b)
   True  + True  == These (a -> e) (a -> b) -- "a" effectively appears twice

  predicates appear first unlike 'Data.Bool.bool'
-}
boolThese ::
  (a -> Bool) ->
  (a -> Bool) ->
  (a -> e) ->
  (a -> b) ->
  a ->
  These e b
boolThese :: (a -> Bool)
-> (a -> Bool) -> (a -> e) -> (a -> b) -> a -> These e b
boolThese a -> Bool
p a -> Bool
q a -> e
l a -> b
r = (a -> Bool)
-> (a -> Bool)
-> (a -> e)
-> (a -> b)
-> ((e, b) -> a -> (e, b))
-> a
-> These e b
forall a e b.
(a -> Bool)
-> (a -> Bool)
-> (a -> e)
-> (a -> b)
-> ((e, b) -> a -> (e, b))
-> a
-> These e b
boolThese' a -> Bool
p a -> Bool
q a -> e
l a -> b
r (e, b) -> a -> (e, b)
forall a b. a -> b -> a
const

{- | similar to 'boolThese' but allows you to override the 'These' case

 predicates appear first unlike 'Data.Bool.bool'
-}
boolThese' ::
  (a -> Bool) ->
  (a -> Bool) ->
  (a -> e) ->
  (a -> b) ->
  ((e, b) -> a -> (e, b)) ->
  a ->
  These e b
boolThese' :: (a -> Bool)
-> (a -> Bool)
-> (a -> e)
-> (a -> b)
-> ((e, b) -> a -> (e, b))
-> a
-> These e b
boolThese' a -> Bool
p a -> Bool
q a -> e
l a -> b
r (e, b) -> a -> (e, b)
b a
a =
  case (a -> Bool
p a
a, a -> Bool
q a
a) of
    (Bool
False, Bool
_) -> e -> These e b
forall a b. a -> These a b
This (a -> e
l a
a)
    (Bool
True, Bool
False) -> b -> These e b
forall a b. b -> These a b
That (a -> b
r a
a)
    (Bool
True, Bool
True) -> (e -> b -> These e b) -> (e, b) -> These e b
forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry e -> b -> These e b
forall a b. a -> b -> These a b
These ((e, b) -> a -> (e, b)
b (a -> e
l a
a, a -> b
r a
a) a
a)

-- | 'Control.Monad.unless' but makes the "a" parameter available to the callback
unlessMB ::
  Applicative m =>
  (a -> Bool) ->
  a ->
  (a -> m ()) ->
  m ()
unlessMB :: (a -> Bool) -> a -> (a -> m ()) -> m ()
unlessMB a -> Bool
p a
a a -> m ()
m = m () -> m () -> Bool -> m ()
forall a. a -> a -> Bool -> a
bool (a -> m ()
m a
a) (() -> m ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()) (a -> Bool
p a
a)

-- | 'Control.Monad.when' but makes the "a" parameter available to the callback
whenMB ::
  Applicative m =>
  (a -> Bool) ->
  a ->
  (a -> m ()) ->
  m ()
whenMB :: (a -> Bool) -> a -> (a -> m ()) -> m ()
whenMB a -> Bool
p a
a a -> m ()
m = m () -> m () -> Bool -> m ()
forall a. a -> a -> Bool -> a
bool (() -> m ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()) (a -> m ()
m a
a) (a -> Bool
p a
a)