module Language.Hakaru.Syntax.Datum
(
Datum(..), datumHint, datumType
, DatumCode(..)
, DatumStruct(..)
, DatumFun(..)
, dTrue, dFalse
, dUnit
, dPair
, dLeft, dRight
, dNil, dCons
, dNothing, dJust
, dPair_
, dLeft_, dRight_
, dNil_, dCons_
, dNothing_, dJust_
, Branch(..)
, Pattern(..)
, PDatumCode(..)
, PDatumStruct(..)
, PDatumFun(..)
, pTrue, pFalse
, pUnit
, pPair
, pLeft, pRight
, pNil, pCons
, pNothing, pJust
, GBranch(..)
) where
import qualified Data.Text as Text
import Data.Text (Text)
#if __GLASGOW_HASKELL__ < 710
import Data.Monoid (Monoid(..))
import Control.Applicative
#endif
import qualified Data.Foldable as F
import qualified Data.Traversable as T
import Language.Hakaru.Syntax.IClasses
import Language.Hakaru.Syntax.Variable (Variable(..))
import Language.Hakaru.Types.DataKind
import Language.Hakaru.Types.Sing
#if __PARTIAL_DATUM_JMEQ__
cannotProve :: String -> a
cannotProve fun =
error $ "Language.Hakaru.Syntax.Datum." ++ fun ++ ": Cannot prove Refl because of phantomness"
#endif
data Datum :: (Hakaru -> *) -> Hakaru -> * where
Datum
:: !Text
-> !(Sing (HData' t))
-> !(DatumCode (Code t) ast (HData' t))
-> Datum ast (HData' t)
datumHint :: Datum ast (HData' t) -> Text
datumHint (Datum hint _ _) = hint
datumType :: Datum ast (HData' t) -> Sing (HData' t)
datumType (Datum _ typ _) = typ
instance Eq1 ast => JmEq1 (Datum ast) where
jmEq1 (Datum _ typ1 d1) (Datum _ typ2 d2) =
case jmEq1 typ1 typ2 of
Just proof@Refl
| eq1 d1 d2 -> Just proof
_ -> Nothing
instance Eq1 ast => Eq1 (Datum ast) where
eq1 (Datum _ _ d1) (Datum _ _ d2) = eq1 d1 d2
instance Eq1 ast => Eq (Datum ast a) where
(==) = eq1
instance Show1 ast => Show1 (Datum ast) where
showsPrec1 p (Datum hint typ d) =
showParen_011 p "Datum" hint typ d
instance Show1 ast => Show (Datum ast a) where
showsPrec = showsPrec1
show = show1
instance Functor11 Datum where
fmap11 f (Datum hint typ d) = Datum hint typ (fmap11 f d)
instance Foldable11 Datum where
foldMap11 f (Datum _ _ d) = foldMap11 f d
instance Traversable11 Datum where
traverse11 f (Datum hint typ d) = Datum hint typ <$> traverse11 f d
infixr 7 `Et`, `PEt`
data DatumCode :: [[HakaruFun]] -> (Hakaru -> *) -> Hakaru -> * where
Inr :: !(DatumCode xss abt a) -> DatumCode (xs ': xss) abt a
Inl :: !(DatumStruct xs abt a) -> DatumCode (xs ': xss) abt a
#if __PARTIAL_DATUM_JMEQ__
instance JmEq1 ast => JmEq1 (DatumCode xss ast) where
jmEq1 (Inr c) (Inr d) = jmEq1 c d
jmEq1 (Inl c) (Inl d) = jmEq1 c d
jmEq1 _ _ = Nothing
#endif
instance Eq1 ast => Eq1 (DatumCode xss ast) where
eq1 (Inr c) (Inr d) = eq1 c d
eq1 (Inl c) (Inl d) = eq1 c d
eq1 _ _ = False
instance Eq1 ast => Eq (DatumCode xss ast a) where
(==) = eq1
instance Show1 ast => Show1 (DatumCode xss ast) where
showsPrec1 p (Inr d) = showParen_1 p "Inr" d
showsPrec1 p (Inl d) = showParen_1 p "Inl" d
instance Show1 ast => Show (DatumCode xss ast a) where
showsPrec = showsPrec1
show = show1
instance Functor11 (DatumCode xss) where
fmap11 f (Inr d) = Inr (fmap11 f d)
fmap11 f (Inl d) = Inl (fmap11 f d)
instance Foldable11 (DatumCode xss) where
foldMap11 f (Inr d) = foldMap11 f d
foldMap11 f (Inl d) = foldMap11 f d
instance Traversable11 (DatumCode xss) where
traverse11 f (Inr d) = Inr <$> traverse11 f d
traverse11 f (Inl d) = Inl <$> traverse11 f d
data DatumStruct :: [HakaruFun] -> (Hakaru -> *) -> Hakaru -> * where
Et :: !(DatumFun x abt a)
-> !(DatumStruct xs abt a)
-> DatumStruct (x ': xs) abt a
Done :: DatumStruct '[] abt a
#if __PARTIAL_DATUM_JMEQ__
instance JmEq1 ast => JmEq1 (DatumStruct xs ast) where
jmEq1 (Et c1 Done) (Et d1 Done) = jmEq1 c1 d1
jmEq1 (Et c1 c2) (Et d1 d2) = do
Refl <- jmEq1 c1 d1
Refl <- jmEq1 c2 d2
Just Refl
jmEq1 Done Done = Just (cannotProve "jmEq1@DatumStruct{Done}")
jmEq1 _ _ = Nothing
#endif
instance Eq1 ast => Eq1 (DatumStruct xs ast) where
eq1 (Et c1 c2) (Et d1 d2) = eq1 c1 d1 && eq1 c2 d2
eq1 Done Done = True
eq1 _ _ = False
instance Eq1 ast => Eq (DatumStruct xs ast a) where
(==) = eq1
instance Show1 ast => Show1 (DatumStruct xs ast) where
showsPrec1 p (Et d1 d2) = showParen_11 p "Et" d1 d2
showsPrec1 _ Done = showString "Done"
instance Show1 ast => Show (DatumStruct xs ast a) where
showsPrec = showsPrec1
show = show1
instance Functor11 (DatumStruct xs) where
fmap11 f (Et d1 d2) = Et (fmap11 f d1) (fmap11 f d2)
fmap11 _ Done = Done
instance Foldable11 (DatumStruct xs) where
foldMap11 f (Et d1 d2) = foldMap11 f d1 `mappend` foldMap11 f d2
foldMap11 _ Done = mempty
instance Traversable11 (DatumStruct xs) where
traverse11 f (Et d1 d2) = Et <$> traverse11 f d1 <*> traverse11 f d2
traverse11 _ Done = pure Done
data DatumFun :: HakaruFun -> (Hakaru -> *) -> Hakaru -> * where
Konst :: !(ast b) -> DatumFun ('K b) ast a
Ident :: !(ast a) -> DatumFun 'I ast a
#if __PARTIAL_DATUM_JMEQ__
instance JmEq1 ast => JmEq1 (DatumFun x ast) where
jmEq1 (Konst e) (Konst f) = do
Refl <- jmEq1 e f
Just (cannotProve "jmEq1@DatumFun{Konst}")
jmEq1 (Ident e) (Ident f) = jmEq1 e f
jmEq1 _ _ = Nothing
#endif
instance Eq1 ast => Eq1 (DatumFun x ast) where
eq1 (Konst e) (Konst f) = eq1 e f
eq1 (Ident e) (Ident f) = eq1 e f
eq1 _ _ = False
instance Eq1 ast => Eq (DatumFun x ast a) where
(==) = eq1
instance Show1 ast => Show1 (DatumFun x ast) where
showsPrec1 p (Konst e) = showParen_1 p "Konst" e
showsPrec1 p (Ident e) = showParen_1 p "Ident" e
instance Show1 ast => Show (DatumFun x ast a) where
showsPrec = showsPrec1
show = show1
instance Functor11 (DatumFun x) where
fmap11 f (Konst e) = Konst (f e)
fmap11 f (Ident e) = Ident (f e)
instance Foldable11 (DatumFun x) where
foldMap11 f (Konst e) = f e
foldMap11 f (Ident e) = f e
instance Traversable11 (DatumFun x) where
traverse11 f (Konst e) = Konst <$> f e
traverse11 f (Ident e) = Ident <$> f e
dTrue, dFalse :: Datum ast HBool
dTrue = Datum tdTrue sBool . Inl $ Done
dFalse = Datum tdFalse sBool . Inr . Inl $ Done
dUnit :: Datum ast HUnit
dUnit = Datum tdUnit sUnit . Inl $ Done
dPair :: (SingI a, SingI b) => ast a -> ast b -> Datum ast (HPair a b)
dPair = dPair_ sing sing
dPair_ :: Sing a -> Sing b -> ast a -> ast b -> Datum ast (HPair a b)
dPair_ a b x y =
Datum tdPair (sPair a b) . Inl $ Konst x `Et` Konst y `Et` Done
dLeft :: (SingI a, SingI b) => ast a -> Datum ast (HEither a b)
dLeft = dLeft_ sing sing
dLeft_ :: Sing a -> Sing b -> ast a -> Datum ast (HEither a b)
dLeft_ a b =
Datum tdLeft (sEither a b) . Inl . (`Et` Done) . Konst
dRight :: (SingI a, SingI b) => ast b -> Datum ast (HEither a b)
dRight = dRight_ sing sing
dRight_ :: Sing a -> Sing b -> ast b -> Datum ast (HEither a b)
dRight_ a b =
Datum tdRight (sEither a b) . Inr . Inl . (`Et` Done) . Konst
dNil :: (SingI a) => Datum ast (HList a)
dNil = dNil_ sing
dNil_ :: Sing a -> Datum ast (HList a)
dNil_ a = Datum tdNil (sList a) . Inl $ Done
dCons :: (SingI a) => ast a -> ast (HList a) -> Datum ast (HList a)
dCons = dCons_ sing
dCons_ :: Sing a -> ast a -> ast (HList a) -> Datum ast (HList a)
dCons_ a x xs =
Datum tdCons (sList a) . Inr . Inl $ Konst x `Et` Ident xs `Et` Done
dNothing :: (SingI a) => Datum ast (HMaybe a)
dNothing = dNothing_ sing
dNothing_ :: Sing a -> Datum ast (HMaybe a)
dNothing_ a = Datum tdNothing (sMaybe a) $ Inl Done
dJust :: (SingI a) => ast a -> Datum ast (HMaybe a)
dJust = dJust_ sing
dJust_ :: Sing a -> ast a -> Datum ast (HMaybe a)
dJust_ a = Datum tdJust (sMaybe a) . Inr . Inl . (`Et` Done) . Konst
tdTrue, tdFalse, tdUnit, tdPair, tdLeft, tdRight, tdNil, tdCons, tdNothing, tdJust :: Text
tdTrue = Text.pack "true"
tdFalse = Text.pack "false"
tdUnit = Text.pack "unit"
tdPair = Text.pack "pair"
tdLeft = Text.pack "left"
tdRight = Text.pack "right"
tdNil = Text.pack "nil"
tdCons = Text.pack "cons"
tdNothing = Text.pack "nothing"
tdJust = Text.pack "just"
data Pattern :: [Hakaru] -> Hakaru -> * where
PWild :: Pattern '[] a
PVar :: Pattern '[ a ] a
PDatum
:: !Text
-> !(PDatumCode (Code t) vars (HData' t))
-> Pattern vars (HData' t)
#if __PARTIAL_DATUM_JMEQ__
instance JmEq2 Pattern where
jmEq2 PWild PWild = Just (Refl, cannotProve "jmEq2@Pattern{PWild}")
jmEq2 PVar PVar = Just (cannotProve "jmEq2@Pattern{PVar}", cannotProve "jmEq2@Pattern{PVar}")
jmEq2 (PDatum _ d1) (PDatum _ d2) =
jmEq2_fake d1 d2
where
jmEq2_fake
:: PDatumCode xss vars1 a1
-> PDatumCode xss' vars2 a2
-> Maybe (TypeEq vars1 vars2, TypeEq a1 a2)
jmEq2_fake =
error "jmEq2@Pattern{PDatum}: can't recurse because Code isn't injective"
jmEq2 _ _ = Nothing
instance JmEq1 (Pattern vars) where
jmEq1 p1 p2 = jmEq2 p1 p2 >>= \(_,proof) -> Just proof
#endif
instance Eq2 Pattern where
eq2 PWild PWild = True
eq2 PVar PVar = True
eq2 (PDatum _ d1) (PDatum _ d2) = eq2 d1 d2
eq2 _ _ = False
instance Eq1 (Pattern vars) where
eq1 = eq2
instance Eq (Pattern vars a) where
(==) = eq1
instance Show2 Pattern where
showsPrec2 _ PWild = showString "PWild"
showsPrec2 _ PVar = showString "PVar"
showsPrec2 p (PDatum hint d) = showParen_02 p "PDatum" hint d
instance Show1 (Pattern vars) where
showsPrec1 = showsPrec2
show1 = show2
instance Show (Pattern vars a) where
showsPrec = showsPrec1
show = show1
data PDatumCode :: [[HakaruFun]] -> [Hakaru] -> Hakaru -> * where
PInr :: !(PDatumCode xss vars a) -> PDatumCode (xs ': xss) vars a
PInl :: !(PDatumStruct xs vars a) -> PDatumCode (xs ': xss) vars a
#if __PARTIAL_DATUM_JMEQ__
instance JmEq2 (PDatumCode xss) where
jmEq2 (PInr c) (PInr d) = jmEq2 c d
jmEq2 (PInl c) (PInl d) = jmEq2 c d
jmEq2 _ _ = Nothing
instance JmEq1 (PDatumCode xss vars) where
jmEq1 (PInr c) (PInr d) = jmEq1 c d
jmEq1 (PInl c) (PInl d) = jmEq1 c d
jmEq1 _ _ = Nothing
#endif
instance Eq2 (PDatumCode xss) where
eq2 (PInr c) (PInr d) = eq2 c d
eq2 (PInl c) (PInl d) = eq2 c d
eq2 _ _ = False
instance Eq1 (PDatumCode xss vars) where
eq1 = eq2
instance Eq (PDatumCode xss vars a) where
(==) = eq1
instance Show2 (PDatumCode xss) where
showsPrec2 p (PInr d) = showParen_2 p "PInr" d
showsPrec2 p (PInl d) = showParen_2 p "PInl" d
instance Show1 (PDatumCode xss vars) where
showsPrec1 = showsPrec2
show1 = show2
instance Show (PDatumCode xss vars a) where
showsPrec = showsPrec1
show = show1
data PDatumStruct :: [HakaruFun] -> [Hakaru] -> Hakaru -> * where
PEt :: !(PDatumFun x vars1 a)
-> !(PDatumStruct xs vars2 a)
-> PDatumStruct (x ': xs) (vars1 ++ vars2) a
PDone :: PDatumStruct '[] '[] a
jmEq_P :: Pattern vs a -> Pattern ws a -> Maybe (TypeEq vs ws)
jmEq_P PWild PWild = Just Refl
jmEq_P PVar PVar = Just Refl
jmEq_P (PDatum _ p1) (PDatum _ p2) = jmEq_PCode p1 p2
jmEq_P _ _ = Nothing
jmEq_PCode
:: PDatumCode xss vs a
-> PDatumCode xss ws a
-> Maybe (TypeEq vs ws)
jmEq_PCode (PInr p1) (PInr p2) = jmEq_PCode p1 p2
jmEq_PCode (PInl p1) (PInl p2) = jmEq_PStruct p1 p2
jmEq_PCode _ _ = Nothing
jmEq_PStruct
:: PDatumStruct xs vs a
-> PDatumStruct xs ws a
-> Maybe (TypeEq vs ws)
jmEq_PStruct (PEt c1 c2) (PEt d1 d2) = do
Refl <- jmEq_PFun c1 d1
Refl <- jmEq_PStruct c2 d2
Just Refl
jmEq_PStruct PDone PDone = Just Refl
jmEq_PStruct _ _ = Nothing
jmEq_PFun :: PDatumFun f vs a -> PDatumFun f ws a -> Maybe (TypeEq vs ws)
jmEq_PFun (PKonst p1) (PKonst p2) = jmEq_P p1 p2
jmEq_PFun (PIdent p1) (PIdent p2) = jmEq_P p1 p2
jmEq_PFun _ _ = Nothing
#if __PARTIAL_DATUM_JMEQ__
instance JmEq2 (PDatumStruct xs) where
jmEq2 (PEt c1 c2) (PEt d1 d2) = do
(Refl, Refl) <- jmEq2 c1 d1
(Refl, Refl) <- jmEq2 c2 d2
Just (Refl, Refl)
jmEq2 PDone PDone = Just (Refl, cannotProve "jmEq2@PDatumStruct{PDone}")
jmEq2 _ _ = Nothing
instance JmEq1 (PDatumStruct xs vars) where
jmEq1 p1 p2 = jmEq2 p1 p2 >>= \(_,proof) -> Just proof
#endif
instance Eq2 (PDatumStruct xs) where
eq2 p1 p2 = maybe False (const True) $ jmEq_PStruct p1 p2
instance Eq1 (PDatumStruct xs vars) where
eq1 = eq2
instance Eq (PDatumStruct xs vars a) where
(==) = eq1
instance Show2 (PDatumStruct xs) where
showsPrec2 p (PEt d1 d2) = showParen_22 p "PEt" d1 d2
showsPrec2 _ PDone = showString "PDone"
instance Show1 (PDatumStruct xs vars) where
showsPrec1 = showsPrec2
show1 = show2
instance Show (PDatumStruct xs vars a) where
showsPrec = showsPrec1
show = show1
data PDatumFun :: HakaruFun -> [Hakaru] -> Hakaru -> * where
PKonst :: !(Pattern vars b) -> PDatumFun ('K b) vars a
PIdent :: !(Pattern vars a) -> PDatumFun 'I vars a
#if __PARTIAL_DATUM_JMEQ__
instance JmEq2 (PDatumFun x) where
jmEq2 (PKonst p1) (PKonst p2) = do
(Refl, Refl) <- jmEq2 p1 p2
Just (Refl, cannotProve "jmEq2@PDatumFun{PKonst}")
jmEq2 (PIdent p1) (PIdent p2) = jmEq2 p1 p2
jmEq2 _ _ = Nothing
instance JmEq1 (PDatumFun x vars) where
jmEq1 (PKonst e) (PKonst f) = do
Refl <- jmEq1 e f
Just (cannotProve "jmEq1@PDatumFun{PKonst}")
jmEq1 (PIdent e) (PIdent f) = jmEq1 e f
jmEq1 _ _ = Nothing
#endif
instance Eq2 (PDatumFun x) where
eq2 (PKonst e) (PKonst f) = eq2 e f
eq2 (PIdent e) (PIdent f) = eq2 e f
eq2 _ _ = False
instance Eq1 (PDatumFun x vars) where
eq1 = eq2
instance Eq (PDatumFun x vars a) where
(==) = eq1
instance Show2 (PDatumFun x) where
showsPrec2 p (PKonst e) = showParen_2 p "PKonst" e
showsPrec2 p (PIdent e) = showParen_2 p "PIdent" e
instance Show1 (PDatumFun x vars) where
showsPrec1 = showsPrec2
show1 = show2
instance Show (PDatumFun x vars a) where
showsPrec = showsPrec1
show = show1
pTrue, pFalse :: Pattern '[] HBool
pTrue = PDatum tdTrue . PInl $ PDone
pFalse = PDatum tdFalse . PInr . PInl $ PDone
pUnit :: Pattern '[] HUnit
pUnit = PDatum tdUnit . PInl $ PDone
varsOfPattern :: Pattern vars a -> proxy vars
varsOfPattern _ = error "TODO: varsOfPattern"
pPair
:: Pattern vars1 a
-> Pattern vars2 b
-> Pattern (vars1 ++ vars2) (HPair a b)
pPair x y =
case eqAppendIdentity (varsOfPattern y) of
Refl -> PDatum tdPair . PInl $ PKonst x `PEt` PKonst y `PEt` PDone
pLeft :: Pattern vars a -> Pattern vars (HEither a b)
pLeft x =
case eqAppendIdentity (varsOfPattern x) of
Refl -> PDatum tdLeft . PInl $ PKonst x `PEt` PDone
pRight :: Pattern vars b -> Pattern vars (HEither a b)
pRight y =
case eqAppendIdentity (varsOfPattern y) of
Refl -> PDatum tdRight . PInr . PInl $ PKonst y `PEt` PDone
pNil :: Pattern '[] (HList a)
pNil = PDatum tdNil . PInl $ PDone
pCons :: Pattern vars1 a
-> Pattern vars2 (HList a)
-> Pattern (vars1 ++ vars2) (HList a)
pCons x xs =
case eqAppendIdentity (varsOfPattern xs) of
Refl -> PDatum tdCons . PInr . PInl $ PKonst x `PEt` PIdent xs `PEt` PDone
pNothing :: Pattern '[] (HMaybe a)
pNothing = PDatum tdNothing . PInl $ PDone
pJust :: Pattern vars a -> Pattern vars (HMaybe a)
pJust x =
case eqAppendIdentity (varsOfPattern x) of
Refl -> PDatum tdJust . PInr . PInl $ PKonst x `PEt` PDone
data Branch
(a :: Hakaru)
(abt :: [Hakaru] -> Hakaru -> *)
(b :: Hakaru)
= forall xs. Branch
!(Pattern xs a)
!(abt xs b)
instance Eq2 abt => Eq1 (Branch a abt) where
eq1 (Branch p1 e1) (Branch p2 e2) =
case jmEq_P p1 p2 of
Nothing -> False
Just Refl -> eq2 e1 e2
instance Eq2 abt => Eq (Branch a abt b) where
(==) = eq1
instance Show2 abt => Show1 (Branch a abt) where
showsPrec1 p (Branch pat e) = showParen_22 p "Branch" pat e
instance Show2 abt => Show (Branch a abt b) where
showsPrec = showsPrec1
show = show1
instance Functor21 (Branch a) where
fmap21 f (Branch p e) = Branch p (f e)
instance Foldable21 (Branch a) where
foldMap21 f (Branch _ e) = f e
instance Traversable21 (Branch a) where
traverse21 f (Branch pat e) = Branch pat <$> f e
data GBranch (a :: Hakaru) (r :: *)
= forall xs. GBranch
!(Pattern xs a)
!(List1 Variable xs)
r
instance Functor (GBranch a) where
fmap f (GBranch pat vars x) = GBranch pat vars (f x)
instance F.Foldable (GBranch a) where
foldMap f (GBranch _ _ x) = f x
instance T.Traversable (GBranch a) where
traverse f (GBranch pat vars x) = GBranch pat vars <$> f x