packages feed

primus-0.1.0.0: src/Primus/Bool.hs

{-# 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 mb mf mt = mb >>= bool mf 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 p r a
  | p a = Just (r a)
  | otherwise = 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 p l r a
  | p a = Right (r a)
  | otherwise = Left (l 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 p q l r = boolThese' p q l r 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' p q l r b a =
  case (p a, q a) of
    (False, _) -> This (l a)
    (True, False) -> That (r a)
    (True, True) -> uncurry These (b (l a, r a) a)

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

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