{-# LANGUAGE ConstraintKinds #-} -- For type class synonyms {-# LANGUAGE PolyKinds #-} {-# LANGUAGE DefaultSignatures #-} -- For adding LiftDerived* constraints module Symantic.Dityped.Derive where import Data.Function ((.)) import Data.Kind (Type) -- * Type family 'Derived' -- | The representation that @(repr)@ derives to. type family Derived (repr :: Type -> Type -> Type) :: Type -> Type -> Type -- * Class 'Derive' -- | Derive an interpreter to a another interpreter -- determined by the 'Derived' open type family. -- This is mostly useful when running the interpreter stack, -- but also when going back from an initial encoding to a final one. -- -- Note that 'derive' and 'liftDerived' are not necessarily reciprocical functions. class Derive repr where derive :: repr a ka -> Derived repr a ka -- * Class 'LiftDerived' -- | Lift the 'Derived' interpreter of an interpreter, to that interpreter. -- This is mostly useful to give default values to class methods -- in order to skip their definition for interpreters -- where 'liftDerived' can already apply the right semantic. -- -- Note that 'derive' and 'liftDerived' are not necessarily reciprocical functions. class LiftDerived repr where liftDerived :: Derived repr a ka -> repr a ka -- * Class 'LiftDerived1' -- | Convenient wrapper of 'derive' and 'liftDerived' for functions with a single argument. class LiftDerived1 repr where liftDerived1 :: (Derived repr a ka -> Derived repr b kb) -> repr a ka -> repr b kb liftDerived1 f = liftDerived . f . derive default liftDerived1 :: LiftDerived repr => Derive repr => (Derived repr a ka -> Derived repr b kb) -> repr a ka -> repr b kb -- * Class 'LiftDerived2' -- | Convenient wrapper of 'derive' and 'liftDerived' for functions with two arguments. class LiftDerived2 repr where liftDerived2 :: (Derived repr a ka -> Derived repr b kb -> Derived repr c kc) -> repr a ka -> repr b kb -> repr c kc liftDerived2 f a b = liftDerived (f (derive a) (derive b)) default liftDerived2 :: LiftDerived repr => Derive repr => (Derived repr a ka -> Derived repr b kb -> Derived repr c kc) -> repr a ka -> repr b kb -> repr c kc -- * Class 'LiftDerived3' -- | Convenient wrapper of 'derive' and 'liftDerived' for functions with three arguments. class LiftDerived3 repr where liftDerived3 :: (Derived repr a ka -> Derived repr b kb -> Derived repr c kc -> Derived repr d kd) -> repr a ka -> repr b kb -> repr c kc -> repr d kd liftDerived3 f a b c = liftDerived (f (derive a) (derive b) (derive c)) default liftDerived3 :: LiftDerived repr => Derive repr => (Derived repr a ka -> Derived repr b kb -> Derived repr c kc -> Derived repr d kd) -> repr a ka -> repr b kb -> repr c kc -> repr d kd -- * Class 'LiftDerived4' -- | Convenient wrapper of 'derive' and 'liftDerived' for functions with three arguments. class LiftDerived4 repr where liftDerived4 :: (Derived repr a ka -> Derived repr b kb -> Derived repr c kc -> Derived repr d kd -> Derived repr e ke) -> repr a ka -> repr b kb -> repr c kc -> repr d kd -> repr e ke liftDerived4 f a b c d = liftDerived (f (derive a) (derive b) (derive c) (derive d)) default liftDerived4 :: LiftDerived repr => Derive repr => (Derived repr a ka -> Derived repr b kb -> Derived repr c kc -> Derived repr d kd -> Derived repr e ke) -> repr a ka -> repr b kb -> repr c kc -> repr d kd -> repr e ke -- * Type synonyms @FromDerived*@ -- | Convenient type synonym for using 'liftDerived' on symantic class @(sym)@. type FromDerived sym repr = ( LiftDerived repr, sym (Derived repr) ) type FromDerived1 sym repr = ( LiftDerived1 repr, sym (Derived repr) ) type FromDerived2 sym repr = ( LiftDerived2 repr, sym (Derived repr) ) type FromDerived3 sym repr = ( LiftDerived3 repr, sym (Derived repr) ) type FromDerived4 sym repr = ( LiftDerived4 repr, sym (Derived repr) )