packages feed

type-rig-0.1: lib/Data/TypeRig/Summable.hs

module Data.TypeRig.Summable where

import Control.Applicative
import Control.Arrow
import Control.Category
import Data.Either
import Data.Functor
import Data.Functor.Invariant
import Data.Kind
import Data.Semigroup
import Data.Void
import Prelude hiding ((.), id)
import qualified Text.ParserCombinators.ReadPrec as ReadPrec

infixr 2 <+++>

-- | Composability via type sum 'Either' and empty type 'Void'.
type Summable :: (Type -> Type) -> Constraint
class Invariant f => Summable f where
    rVoid :: f Void
    default rVoid :: Alternative f => f Void
    rVoid = empty
    (<+++>) :: f a -> f b -> f (Either a b)
    default (<+++>) :: Alternative f => f a -> f b -> f (Either a b)
    fa <+++> fb = (fmap Left fa) <|> (fmap Right fb)

instance Summable Endo where
    rVoid = Endo id
    Endo p <+++> Endo q =
        Endo $ \case
            Left a -> Left $ p a
            Right b -> Right $ q b

instance Summable m => Summable (Kleisli m a) where
    rVoid = Kleisli $ \_ -> rVoid
    Kleisli p <+++> Kleisli q = Kleisli $ \a -> p a <+++> q a

instance Summable ReadPrec.ReadPrec where
    ra <+++> rb = fmap Left ra ReadPrec.<++ fmap Right rb