module Symantic.Base.Composable where import Data.Function ((.)) -- * Class 'Composable' class Composable repr where default (<.>) :: Transformable repr => Composable (UnTrans repr) => repr a b -> repr b c -> repr a c (<.>) :: repr a b -> repr b c -> repr a c x <.> y = noTrans (unTrans x <.> unTrans y) infixr 4 <.> -- * Class 'Voidable' class Voidable repr where default void :: Transformable repr => Voidable (UnTrans repr) => a -> repr (a -> b) k -> repr b k void :: a -> repr (a -> b) k -> repr b k void a = noTrans . void a . unTrans -- * Class 'Transformable' -- | Used with @DefaultSignatures@ and default methods, -- in the symantics class definition, -- it then avoids on an interpreter instance -- to define unused methods. class Transformable repr where -- | The underlying representation that @(repr)@ transforms. type UnTrans repr :: * -> * -> * -- | Lift the underlying representation to @(repr)@. -- Useful to define a combinator that does nothing -- in a transformation. noTrans :: UnTrans repr a b -> repr a b -- | Unlift a representation. Useful when a transformation -- combinator needs to access the 'UnTrans'formed representation, -- or at the end to get the underlying 'UnTrans'formed representation -- from the inferred @(repr)@ value. unTrans :: repr a b -> UnTrans repr a b -- ** Type 'IdentityTrans' -- | A 'Transformable' that does nothing. newtype IdentityTrans repr a k = IdentityTrans { unIdentityTrans :: repr a k } instance Transformable (IdentityTrans repr) where type UnTrans (IdentityTrans repr) = repr noTrans = IdentityTrans unTrans = unIdentityTrans -- * Class 'Dimapable' class Dimapable repr where default dimap :: Transformable repr => Dimapable (UnTrans repr) => (a->b) -> (b->a) -> repr (a->k) k -> repr (b->k) k dimap :: (a->b) -> (b->a) -> repr (a->k) k -> repr (b->k) k dimap a2b b2a = noTrans . dimap a2b b2a . unTrans