packages feed

associative-0.0.3: src/Data/Associative.hs

{-# OPTIONS_GHC -Wall -Werror #-}

-- |
-- Associative binary operations as first-class values, with a monad-transformer
-- structure for composing effects. Includes both total and partial variants, each
-- with semigroup and monoid flavours.
--
-- Four modules are provided:
--
-- +--------------------------------------------------+----------------------------------------------+-----------------------------------------------------------+
-- | Module                                           | Type                                         | Operation                                                 |
-- +==================================================+==============================================+===========================================================+
-- | "Data.Associative.SemigroupOp"                   | @SemigroupOpT f a b@ ~ @a -> a -> f b@       | Total semigroup -- defined for all inputs                 |
-- +--------------------------------------------------+----------------------------------------------+-----------------------------------------------------------+
-- | "Data.Associative.PartialSemigroupOp"            | @PartialSemigroupOpT f a b@ ~ @a -> a -> f (Maybe b)@ | Partial semigroup -- may be undefined for some inputs |
-- +--------------------------------------------------+----------------------------------------------+-----------------------------------------------------------+
-- | "Data.Associative.MonoidOp"                      | @MonoidOp a@ ~ @(SemigroupOp' a, a)@        | Total monoid -- semigroup with an identity element        |
-- +--------------------------------------------------+----------------------------------------------+-----------------------------------------------------------+
-- | "Data.Associative.PartialMonoidOp"               | @PartialMonoidOp a@ ~ @(PartialSemigroupOp' a, a)@ | Partial monoid -- partial semigroup with an identity element |
-- +--------------------------------------------------+----------------------------------------------+-----------------------------------------------------------+
--
-- The semigroup types are parameterised by a functor @f@ for effects (e.g.
-- 'Data.Functor.Identity.Identity', 'IO', @State s@), an input type @a@, and a result type @b@. When
-- @a ~ b@ the operation is /endomorphic/ (the common case for semigroups).
--
-- The monoid types pair a semigroup operation with its identity element.
--
-- == Quick start
--
-- @
-- import "Data.Associative.SemigroupOp"
-- import "Data.Associative.PartialSemigroupOp" ('Data.Associative.PartialSemigroupOp.PartialSemigroupOpT'(..), 'Data.Associative.PartialSemigroupOp.runPartialSemigroupOp', 'Data.Associative.PartialSemigroupOp.total')
-- import "Data.Associative.MonoidOp"
-- import "Data.Associative.PartialMonoidOp"
--
-- -- A total semigroup operation for addition
-- add :: 'Data.Associative.SemigroupOp.SemigroupOp'' Int
-- add = 'Data.Associative.SemigroupOp.op' (+)
--
-- 'Data.Associative.SemigroupOp.runSemigroupOp' add 3 4 -- 7
--
-- -- A partial semigroup that adds two positive integers
-- addPos :: 'Data.Associative.PartialSemigroupOp.PartialSemigroupOp'' Int
-- addPos = 'Data.Associative.PartialSemigroupOp.PartialSemigroupOpT' (\\a b ->
--   Identity (if a > 0 && b > 0 then Just (a + b) else Nothing))
--
-- 'Data.Associative.PartialSemigroupOp.runPartialSemigroupOp' addPos 3 4   -- Just 7
-- 'Data.Associative.PartialSemigroupOp.runPartialSemigroupOp' addPos (-1) 4 -- Nothing
--
-- -- A monoid operation for addition with identity 0
-- addM :: 'Data.Associative.MonoidOp.MonoidOp' Int
-- addM = 'Data.Associative.MonoidOp.MonoidOp' ('Data.Associative.SemigroupOp.op' (+)) 0
--
-- 'Data.Associative.MonoidOp.runMonoidOp' addM 3 4        -- 7
-- 'Data.Associative.MonoidOp.identityMonoidOp' addM       -- 0
--
-- -- A partial monoid operation
-- addPM :: 'Data.Associative.PartialMonoidOp.PartialMonoidOp' Int
-- addPM = 'Data.Associative.PartialMonoidOp.PartialMonoidOp' ('Data.Associative.PartialSemigroupOp.total' (+)) 0
--
-- 'Data.Associative.PartialMonoidOp.runPartialMonoidOp' addPM 3 4        -- Just 7
-- 'Data.Associative.PartialMonoidOp.identityPartialMonoidOp' addPM       -- 0
-- @
--
-- == Smart constructors
--
-- === SemigroupOp
--
-- ['Data.Associative.SemigroupOp.op'] Lift a pure function @(a -> a -> b)@ into a semigroup operation
--
-- ['Data.Associative.SemigroupOp.semigroupSemigroup'] Lift a 'Semigroup' class instance: @semigroupSemigroup = op ('<>')@
--
-- === PartialSemigroupOp
--
-- ['Data.Associative.PartialSemigroupOp.total'] Lift a total pure function @(a -> a -> b)@ into a partial semigroup that always succeeds
--
-- ['Data.Associative.PartialSemigroupOp.totalT'] Lift an effectful total function @(a -> a -> f b)@
--
-- ['Data.Associative.PartialSemigroupOp.psemigroupSemigroup'] Lift a 'Semigroup' class instance: @psemigroupSemigroup = total ('<>')@
--
-- ['Data.Associative.PartialSemigroupOp.null'] The always-undefined partial semigroup
--
-- === MonoidOp
--
-- ['Data.Associative.MonoidOp.monoid'] Lift a 'Monoid' class instance
--
-- ['Data.Associative.MonoidOp.MonoidOp'] Directly pair a 'Data.Associative.SemigroupOp.SemigroupOp'' with its identity element
--
-- === PartialMonoidOp
--
-- ['Data.Associative.PartialMonoidOp.pmonoid'] Lift a 'Monoid' class instance
--
-- ['Data.Associative.PartialMonoidOp.PartialMonoidOp'] Directly pair a 'Data.Associative.PartialSemigroupOp.PartialSemigroupOp'' with its identity element
--
-- == Typeclass instances
--
-- The semigroup types carry a rich set of instances. The monoid types provide
-- classy optics into their underlying semigroup.
--
-- === SemigroupOpT instances
--
-- 'Functor', 'Data.Functor.Apply.Apply', 'Applicative', 'Data.Functor.Bind.Bind', 'Monad', 'Data.Profunctor.Profunctor', 'Data.Profunctor.Strong', 'Data.Profunctor.Choice',
-- 'Data.Semigroupoid.Semigroupoid', 'Semigroup', 'Monoid', 'Control.Selective.Selective', 'Data.Functor.Extend.Extend', 'Control.Lens.Wrapped', 'Control.Lens.Rewrapped',
-- 'Control.Monad.Reader.Class.MonadReader', 'Control.Monad.Error.Class.MonadError', 'Control.Monad.State.Class.MonadState', 'Control.Monad.Writer.Class.MonadWriter', 'Control.Monad.RWS.Class.MonadRWS', 'Control.Monad.IO.Class.MonadIO',
-- 'Control.Monad.Cont.Class.MonadCont', 'Data.Functor.Alt.Alt', 'Data.Functor.Plus.Plus'.
--
-- === PartialSemigroupOpT instances
--
-- All of the above, plus: 'MonadFail', 'Control.Applicative.Alternative', 'Control.Monad.MonadPlus', 'Witherable.Filterable'.
--
-- These additional instances exploit the 'Maybe' layer in @f (Maybe b)@ to
-- express failure and filtering. They are not available on 'Data.Associative.SemigroupOp.SemigroupOpT'
-- because a total operation always produces a result.
--
-- === Semantic differences
--
-- The 'Semigroup' and 'Monoid' instances differ between the two semigroup types:
--
-- ['Data.Associative.PartialSemigroupOp.PartialSemigroupOpT'] First-success fallback. @p '<>' q@ tries @p@ first;
--   if it returns 'Nothing', falls back to @q@. 'mempty' is the
--   always-undefined operation.
--
-- ['Data.Associative.SemigroupOp.SemigroupOpT'] Pointwise combination. @p '<>' q@ runs both and combines
--   their results via the inner 'Semigroup'. 'mempty' returns 'mempty' of the
--   result type. Requires @'Semigroup' b@ \/ @'Monoid' b@ on the result.
--
-- === Classy optics on monoid types
--
-- 'Data.Associative.MonoidOp.MonoidOp' has a 'Data.Associative.SemigroupOp.HasSemigroupOpT' instance giving lens access to the
-- underlying 'Data.Associative.SemigroupOp.SemigroupOp''. 'Data.Associative.PartialMonoidOp.PartialMonoidOp' has a 'Data.Associative.PartialSemigroupOp.HasPartialSemigroupOpT'
-- instance for the same purpose.
--
-- == Pre-defined values
--
-- All four modules export named values for common operations.
--
-- === Via class instance
--
-- @Unit@, @Void@ (semigroups only), @Ordering@, @List@, @NonEmpty@ (semigroups only), @Either@ (semigroups only),
-- @Proxy@, @Maybe@, @Dual@, @Down@, @Identity@, @Tuple@, @WrappedMonoid@,
-- @Function@, @Alt@, @Alternative@.
--
-- === Via op \/ total
--
-- @First@, @Last@ (semigroups only), @Min@, @Max@, @All@, @Any@, @Addition@, @Multiplication@, @Endo@,
-- @And@ (bitwise), @Ior@, @Xor@, @Iff@ (XNOR).
--
-- === Collection operations
--
-- Union and intersection for 'Data.Set.Set', 'Data.IntSet.IntSet', 'Data.HashSet.HashSet', 'Data.Map.Map', 'Data.IntMap.IntMap',
-- 'Data.HashMap.Strict.HashMap'. Monoid types provide union only (intersection lacks a general
-- identity element).
--
-- == Classy optics
--
-- Each semigroup module exports a classy lens and a classy prism:
--
-- @
-- class 'Data.Associative.SemigroupOp.HasSemigroupOpT' c f a b | c -> f a b where
--   'Data.Associative.SemigroupOp.semigroupOpT' :: Lens' c ('Data.Associative.SemigroupOp.SemigroupOpT' f a b)
--
-- class 'Data.Associative.SemigroupOp.AsSemigroupOpT' c f a b | c -> f a b where
--   'Data.Associative.SemigroupOp._SemigroupOpT' :: Prism' c ('Data.Associative.SemigroupOp.SemigroupOpT' f a b)
-- @
--
-- @
-- class 'Data.Associative.PartialSemigroupOp.HasPartialSemigroupOpT' c f a b | c -> f a b where
--   'Data.Associative.PartialSemigroupOp.partialSemigroupOpT' :: Lens' c ('Data.Associative.PartialSemigroupOp.PartialSemigroupOpT' f a b)
--
-- class 'Data.Associative.PartialSemigroupOp.AsPartialSemigroupOpT' c f a b | c -> f a b where
--   'Data.Associative.PartialSemigroupOp._PartialSemigroupOpT' :: Prism' c ('Data.Associative.PartialSemigroupOp.PartialSemigroupOpT' f a b)
-- @
--
-- Each monoid module exports its own classy lens and prism:
--
-- @
-- class 'Data.Associative.MonoidOp.HasMonoidOp' c a | c -> a where
--   'Data.Associative.MonoidOp.monoidOp' :: Lens' c ('Data.Associative.MonoidOp.MonoidOp' a)
--
-- class 'Data.Associative.MonoidOp.AsMonoidOp' c a | c -> a where
--   'Data.Associative.MonoidOp._MonoidOp' :: Prism' c ('Data.Associative.MonoidOp.MonoidOp' a)
-- @
--
-- @
-- class 'Data.Associative.PartialMonoidOp.HasPartialMonoidOp' c a | c -> a where
--   'Data.Associative.PartialMonoidOp.partialMonoidOp' :: Lens' c ('Data.Associative.PartialMonoidOp.PartialMonoidOp' a)
--
-- class 'Data.Associative.PartialMonoidOp.AsPartialMonoidOp' c a | c -> a where
--   'Data.Associative.PartialMonoidOp._PartialMonoidOp' :: Prism' c ('Data.Associative.PartialMonoidOp.PartialMonoidOp' a)
-- @
--
-- == Law-checking functions
--
-- All modules export functions for verifying laws at specific inputs, useful for
-- property-based testing.
--
-- Each module prefixes its law functions with its value prefix
-- (@semigroup@, @psemigroup@, @monoid@, @pmonoid@).
--
-- === Semigroup modules
--
-- * @semigroupLawAssociative@ / @psemigroupLawAssociative@ -- associativity of the binary operation itself
--
-- * @semigroupLawSemigroupAssociative@ / @psemigroupLawSemigroupAssociative@ -- 'Semigroup' instance associativity
--
-- * @semigroupLawMonoidLeftIdentity@ / @psemigroupLawMonoidLeftIdentity@, @semigroupLawMonoidRightIdentity@ / @psemigroupLawMonoidRightIdentity@
--
-- * @semigroupLawFunctorIdentity@ / @psemigroupLawFunctorIdentity@, @semigroupLawFunctorComposition@ / @psemigroupLawFunctorComposition@
--
-- * @semigroupLawProfunctorIdentity@ / @psemigroupLawProfunctorIdentity@
--
-- * @semigroupLawExtendAssociative@ / @psemigroupLawExtendAssociative@
--
-- * @semigroupLawSemigroupoidAssociative@ / @psemigroupLawSemigroupoidAssociative@
--
-- "Data.Associative.PartialSemigroupOp" additionally exports @lawFilterableIdentity@ and
-- @lawFilterableComposition@.
--
-- === Monoid modules
--
-- * @monoidLawAssociative@ / @pmonoidLawAssociative@ -- associativity of the binary operation
--
-- * @monoidLawLeftIdentity@ / @pmonoidLawLeftIdentity@, @monoidLawRightIdentity@ / @pmonoidLawRightIdentity@ -- identity element laws
module Data.Associative
  ( module A,
  )
where

import Data.Associative.MonoidOp as A
import Data.Associative.PartialMonoidOp as A
import Data.Associative.PartialSemigroupOp as A
import Data.Associative.SemigroupOp as A