module Symantic.Base.Algebrable where import Data.Either (Either) import Data.Function ((.)) import Data.Maybe (Maybe(..)) import Data.Proxy (Proxy(..)) import GHC.Generics (Generic) import Symantic.Base.ADT import Symantic.Base.CurryN import Symantic.Base.Composable -- | @('adt' @@SomeADT some_expr)@ -- wrap/unwrap @(some_expr)@ input/output value -- to/from the Algebraic Data Type @(SomeADT)@. -- @(SomeADT)@ must have a 'Generic' instance -- (using the @DeriveGeneric@ language extension to GHC). adt :: forall adt repr k. Dimapable repr => Generic adt => RepOfEoT adt => EoTOfRep adt => repr (EoT (ADT adt) -> k) k -> repr (adt -> k) k adt = dimap adtOfeot eotOfadt -- * Class 'Tupable' class Tupable repr where default (<:>) :: Transformable repr => Tupable (UnTrans repr) => repr (a->k) k -> repr (b->k) k -> repr ((a,b)->k) k (<:>) :: repr (a->k) k -> repr (b->k) k -> repr ((a,b)->k) k x <:> y = noTrans (unTrans x <:> unTrans y) infixr 4 <:> -- ** Class 'Unitable' class Unitable repr where default unit :: Transformable repr => Unitable (UnTrans repr) => repr (() -> k) k unit :: repr (() -> k) k unit = noTrans unit -- ** Class 'Constant' class Constant repr where default constant :: Transformable repr => Constant (UnTrans repr) => a -> repr (a -> k) k constant :: a -> repr (a -> k) k constant = noTrans . constant -- * Class 'Eitherable' class Eitherable repr where default (<+>) :: Transformable repr => Eitherable (UnTrans repr) => repr (a->k) k -> repr (b->k) k -> repr (Either a b -> k) k (<+>) :: repr (a->k) k -> repr (b->k) k -> repr (Either a b->k) k x <+> y = noTrans (unTrans x <+> unTrans y) -- NOTE: yes infixr, not infixl like <|>, -- in order to run left-most checks first. infixr 3 <+> -- ** Class 'Emptyable' class Emptyable repr where default empty :: Transformable repr => Emptyable (UnTrans repr) => repr k k empty :: repr k k empty = noTrans empty -- ** Class 'Optionable' class Optionable repr where default option :: Transformable repr => Optionable (UnTrans repr) => repr k k -> repr k k option :: repr k k -> repr k k option = noTrans . option . unTrans default optional :: Transformable repr => Optionable (UnTrans repr) => repr (a->k) k -> repr (Maybe a->k) k optional :: repr (a->k) k -> repr (Maybe a->k) k optional = noTrans . optional . unTrans -- * Class 'Repeatable' class Repeatable repr where default many0 :: Transformable repr => Repeatable (UnTrans repr) => repr (a->k) k -> repr ([a]->k) k many0 :: repr (a->k) k -> repr ([a]->k) k many0 = noTrans . many0 . unTrans default many1 :: Transformable repr => Repeatable (UnTrans repr) => repr (a->k) k -> repr ([a]->k) k many1 :: repr (a->k) k -> repr ([a]->k) k many1 = noTrans . many1 . unTrans -- * Class 'Substractable' class Substractable repr where default (<->) :: Transformable repr => Substractable (UnTrans repr) => repr a k -> repr k' k' -> repr a k (<->) :: repr a k -> repr k' k' -> repr a k x <-> y = noTrans (unTrans x <-> unTrans y) infixr 3 <-> -- * Class 'Dicurryable' class Dicurryable repr where dicurry :: CurryN args => proxy args -> (args-..->r) -> -- construction (r->Tuples args) -> -- destruction repr (args-..->k) k -> repr (r->k) k default dicurry :: Transformable repr => Dicurryable (UnTrans repr) => CurryN args => proxy args -> (args-..->r) -> (r->Tuples args) -> repr (args-..->k) k -> repr (r->k) k dicurry args constr destr = noTrans . dicurry args constr destr . unTrans construct :: forall args a k repr. Dicurryable repr => Generic a => EoTOfRep a => CurryN args => Tuples args ~ EoT (ADT a) => (args ~ Args (args-..->a)) => (args-..->a) -> repr (args-..->k) k -> repr (a -> k) k construct f = dicurry (Proxy::Proxy args) f eotOfadt