associative-0.0.1: examples/Data/Associative/Examples/PartialSemigroupOpExamples.hs
{-# OPTIONS_GHC -Wall -Werror #-}
-- |
-- Example usages of "Data.Associative.PartialSemigroupOp".
module Data.Associative.Examples.PartialSemigroupOpExamples
( -- * Constructing and running partial semigroups
addPositive,
multiply,
-- * Combining operations with Semigroup (first-success fallback)
fallbackExample,
-- * Functor
fmapPartialExample,
-- * Using effects (monad transformer)
countedAdd,
)
where
import Control.Monad.State (State, get, put)
import Data.Associative.PartialSemigroupOp
( PartialSemigroupOp',
PartialSemigroupOpT (..),
runPartialSemigroupOp,
runPartialSemigroupOpT,
total,
)
import Data.Functor.Identity (Identity (..))
import Prelude hiding (null)
-- $setup
-- >>> import Data.Functor.Identity (Identity(..))
-- >>> import Control.Monad.State (runState)
-- * Constructing and running partial semigroups
-- | A partial semigroup that adds two positive integers,
-- returning 'Nothing' when either input is non-positive.
--
-- >>> runPartialSemigroupOp addPositive 3 4
-- Just 7
-- >>> runPartialSemigroupOp addPositive (-1) 4
-- Nothing
-- >>> runPartialSemigroupOp addPositive 0 5
-- Nothing
addPositive :: PartialSemigroupOp' Int
addPositive =
PartialSemigroupOpT
( \a b ->
Identity
( if a > 0 && b > 0
then Just (a + b)
else Nothing
)
)
-- | A partial semigroup built with the 'total' smart constructor.
-- Total operations always succeed (always return 'Just').
--
-- >>> runPartialSemigroupOp multiply 3 4
-- Just 12
-- >>> runPartialSemigroupOp multiply 0 5
-- Just 0
multiply :: PartialSemigroupOp' Int
multiply = total (*)
-- * Combining operations with Semigroup (first-success fallback)
-- | Partial semigroups combine with first-success fallback:
-- try the left operand; if it returns 'Nothing', try the right.
--
-- >>> runPartialSemigroupOp (addPositive <> total (+)) 3 4
-- Just 7
-- >>> runPartialSemigroupOp (addPositive <> total (+)) (-1) 4
-- Just 3
fallbackExample :: PartialSemigroupOp' Int
fallbackExample = addPositive <> total (+)
-- * Functor
-- | 'fmap' transforms the result.
--
-- >>> runPartialSemigroupOp (fmap (*10) addPositive) 3 4
-- Just 70
-- >>> runPartialSemigroupOp (fmap (*10) addPositive) (-1) 4
-- Nothing
fmapPartialExample :: PartialSemigroupOp' Int
fmapPartialExample = fmap (* 10) addPositive
-- * Using effects (monad transformer)
-- | A partial semigroup that tracks how many times it's been called,
-- returning 'Nothing' when either input is non-positive.
--
-- >>> runState (runPartialSemigroupOpT countedAdd 3 4) 0
-- (Just 7,1)
-- >>> runState (runPartialSemigroupOpT countedAdd (-1) 4) 0
-- (Nothing,1)
countedAdd :: PartialSemigroupOpT (State Int) Int Int
countedAdd =
PartialSemigroupOpT
( \a b -> do
n <- get
put (n + 1)
pure
( if a > 0 && b > 0
then Just (a + b)
else Nothing
)
)
-- helpers to suppress unused-import warnings for re-exports used in doctests
_suppressRunPartialSemigroupOp :: PartialSemigroupOp' a -> a -> a -> Maybe a
_suppressRunPartialSemigroupOp = runPartialSemigroupOp
_suppressRunPartialSemigroupOpT :: PartialSemigroupOpT f a b -> a -> a -> f (Maybe b)
_suppressRunPartialSemigroupOpT = runPartialSemigroupOpT