module Language.Syntactic.Syntax
(
AST (..)
, ASTF
, Full (..)
, (:->) (..)
, size
, ApplySym (..)
, DenResult
, (:+:) (..)
, Project (..)
, (:<:) (..)
, appSym
, symType
, prjP
) where
import Control.Monad.Instances
import Data.Typeable
import Data.PolyProxy
data AST dom sig
where
Sym :: dom sig -> AST dom sig
(:$) :: AST dom (a :-> sig) -> AST dom (Full a) -> AST dom sig
infixl 1 :$
type ASTF dom a = AST dom (Full a)
instance Functor dom => Functor (AST dom)
where
fmap f (Sym s) = Sym (fmap f s)
fmap f (s :$ a) = fmap (fmap f) s :$ a
newtype Full a = Full { result :: a }
deriving (Eq, Show, Typeable, Functor)
newtype a :-> sig = Partial (a -> sig)
deriving (Typeable, Functor)
infixr :->
size :: AST dom sig -> Int
size (Sym _) = 1
size (s :$ a) = size s + size a
class ApplySym sig f dom | sig dom -> f, f -> sig dom
where
appSym' :: AST dom sig -> f
instance ApplySym (Full a) (ASTF dom a) dom
where
appSym' = id
instance ApplySym sig f dom => ApplySym (a :-> sig) (ASTF dom a -> f) dom
where
appSym' sym a = appSym' (sym :$ a)
type family DenResult sig
type instance DenResult (Full a) = a
type instance DenResult (a :-> sig) = DenResult sig
data (dom1 :+: dom2) a
where
InjL :: dom1 a -> (dom1 :+: dom2) a
InjR :: dom2 a -> (dom1 :+: dom2) a
deriving (Functor)
infixr :+:
class Project sub sup
where
prj :: sup a -> Maybe (sub a)
instance Project sub sup => Project sub (AST sup)
where
prj (Sym a) = prj a
prj _ = Nothing
instance Project expr expr
where
prj = Just
instance Project expr1 (expr1 :+: expr2)
where
prj (InjL a) = Just a
prj _ = Nothing
instance Project expr1 expr3 => Project expr1 (expr2 :+: expr3)
where
prj (InjR a) = prj a
prj _ = Nothing
class Project sub sup => sub :<: sup
where
inj :: sub a -> sup a
instance (sub :<: sup) => (sub :<: AST sup)
where
inj = Sym . inj
instance (expr :<: expr)
where
inj = id
instance (expr1 :<: (expr1 :+: expr2))
where
inj = InjL
instance (expr1 :<: expr3) => (expr1 :<: (expr2 :+: expr3))
where
inj = InjR . inj
appSym :: (ApplySym sig f dom, sym :<: AST dom) => sym sig -> f
appSym = appSym' . inj
symType :: P sym -> sym sig -> sym sig
symType _ = id
prjP :: Project sub sup => P sub -> sup sig -> Maybe (sub sig)
prjP _ = prj