eliminators-0.9.1: tests/DecideTypes.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wno-unused-foralls #-}
module DecideTypes where
import Data.Eliminator
import Data.Kind
import Data.Nat
import Data.Singletons.TH hiding (Decision(..))
import Prelude.Singletons (ConstSym1)
-- Due to https://github.com/goldfirere/singletons/issues/82, promoting the
-- Decision data type from Data.Singletons.Decide is a tad awkward. To work
-- around these, we define a more general Decision' data type here.
type Decision' :: (Type ~> Type ~> Type) -> Type -> Type
data Decision' p a
= Proved a
| Disproved (p @@ a @@ Void)
elimDecision :: forall a (p :: PDecision a ~> Type) (d :: PDecision a).
Sing d
-> (forall (yes :: a). Sing yes -> p @@ Proved yes)
-> (forall (no :: a ~> Void). Sing no -> p @@ Disproved no)
-> p @@ d
elimDecision sd pProved pDisproved = go @d sd
where
go :: forall (d' :: PDecision a). Sing d' -> p @@ d'
go (SProved yes) = pProved yes
go (SDisproved no) = pDisproved no
type ElimDecision :: forall a.
forall (p :: PDecision a ~> Type)
(d :: PDecision a) ->
(forall (yes :: a) -> p @@ Proved yes)
-> (forall (no :: a ~> Void) -> p @@ Disproved no)
-> p @@ d
type family ElimDecision p d pProved pDisproved where
forall a (p :: PDecision a ~> Type)
(pProved :: forall (yes :: a) -> p @@ Proved yes)
(pDisproved :: forall (no :: a ~> Void) -> p @@ Disproved no) yes.
ElimDecision p (Proved yes) pProved pDisproved = pProved yes
forall a (p :: PDecision a ~> Type)
(pProved :: forall (yes :: a) -> p @@ Proved yes)
(pDisproved :: forall (no :: a ~> Void) -> p @@ Disproved no) no.
ElimDecision p (Disproved no) pProved pDisproved = pDisproved no
instance Show a => Show (Decision' p a) where
showsPrec p (Proved a) =
showParen (p > 10) $ showString "Proved " . showsPrec 11 a
showsPrec p (Disproved _) =
showParen (p > 10) $ showString "Disproved <void>"
type Decision :: Type -> Type
type Decision = Decision' (TyCon (->))
type PDecision :: Type -> Type
type PDecision = Decision' (~>@#@$)
type SDecision :: PDecision a -> Type
data SDecision d where
SProved :: forall a (x :: a). Sing x -> SDecision (Proved x)
SDisproved :: forall a (r :: a ~> Void). Sing r -> SDecision (Disproved r)
type instance Sing = SDecision
instance SingKind a => SingKind (PDecision a) where
type Demote (PDecision a) = Decision (Demote a)
fromSing (SProved a) = Proved (fromSing a)
fromSing (SDisproved r) = Disproved (fromSing r)
toSing (Proved x) = withSomeSing x $ SomeSing . SProved
toSing (Disproved r) = withSomeSing r $ SomeSing . SDisproved
-----
-- These newtype wrappers are needed to work around
-- https://gitlab.haskell.org/ghc/ghc/issues/9269
type WhyDecEqNat :: Nat -> Type
newtype WhyDecEqNat k = WhyDecEqNat
{ runWhyDecEqNat :: forall (j :: Nat). Sing j -> Decision (k :~: j) }
type WhyDecEqList :: [e] -> Type
newtype WhyDecEqList (l1 :: [e]) = WhyDecEqList
{ runWhyDecEqList :: forall (l2 :: [e]). Sing l2 -> Decision (l1 :~: l2) }
type ConstVoidNat :: Nat -> Type -> Type
type ConstVoidNat m r = Void
-- ElimNat requires an argument of kind (forall (m :: Nat) -> ...), which is
-- not the same thing as (Nat -> ...). Unfortunately, it's not easy to convince
-- singletons-th to generate defunctionalization symbols for ConstVoidNat that
-- have a dependent kind like this. As a result, we have to define
-- defunctionalization symbols by hand with the appropriate kind.
type ConstVoidNatSym :: forall (m :: Nat) -> (Type ~> Type)
data ConstVoidNatSym m z
type instance Apply (ConstVoidNatSym m) r = ConstVoidNat m r
type EqSameNat :: Nat -> Nat -> Type -> Type
type EqSameNat n m r = n :~: m
type EqSameNatSym :: Nat -> forall (m :: Nat) -> (Type ~> Type)
data EqSameNatSym n m z
type instance Apply (EqSameNatSym n m) r = EqSameNat n m r
type ConstVoidList :: e -> [e] -> Type -> Type
type ConstVoidList y ys r = Void
type ConstVoidListSym :: forall e. forall (y :: e) (ys :: [e])
-> (Type ~> Type)
data ConstVoidListSym y ys z
type instance Apply (ConstVoidListSym y ys) r = ConstVoidList y ys r
type EqSameList :: e -> [e] -> e -> [e] -> Type -> Type
type EqSameList x xs y ys r = (x :~: y, xs :~: ys)
type EqSameListSym :: forall e. e -> [e] -> forall (y :: e) (ys :: [e])
-> (Type ~> Type)
data EqSameListSym x xs y ys z
type instance Apply (EqSameListSym x xs y ys) r = EqSameList x xs y ys r
$(singletons [d|
type NatEqConsequencesBase :: Nat -> Type
type NatEqConsequencesBase m = ElimNat (ConstSym1 Type) m () ConstVoidNatSym
type NatEqConsequencesStep :: Nat -> (Nat ~> Type) -> Nat -> Type
type NatEqConsequencesStep m r n = ElimNat (ConstSym1 Type) n Void (EqSameNatSym m)
type ListEqConsequencesBase :: [e] -> Type
type ListEqConsequencesBase ys = ElimList (ConstSym1 Type) ys () ConstVoidListSym
type ListEqConsequencesStep :: e -> [e] -> ([e] ~> Type) -> [e] -> Type
type ListEqConsequencesStep x xs r ys = ElimList (ConstSym1 Type) ys Void (EqSameListSym x xs)
|])
type NatEqConsequencesStepSym :: forall (m :: Nat)
-> (Nat ~> Type) ~> (Nat ~> Type)
data NatEqConsequencesStepSym m z
type instance Apply (NatEqConsequencesStepSym m) r = NatEqConsequencesStepSym2 m r
type ListEqConsequencesStepSym :: forall e. forall (x :: e) (xs :: [e])
-> ([e] ~> Type) ~> ([e] ~> Type)
data ListEqConsequencesStepSym x xs z
type instance Apply (ListEqConsequencesStepSym x xs) r = ListEqConsequencesStepSym3 x xs r
$(singletons [d|
type NatEqConsequences :: Nat -> Nat -> Type
type NatEqConsequences n m =
ElimNat (ConstSym1 (Nat ~> Type)) n
NatEqConsequencesBaseSym0
NatEqConsequencesStepSym @@ m
type WhyNatEqConsequencesSame :: Nat -> Type
type WhyNatEqConsequencesSame a = NatEqConsequences a a
type WhyDecEqZ :: Nat -> Type
type WhyDecEqZ k = Decision (Z :~: k)
type WhyDecEqS :: Nat -> Nat -> Type
type WhyDecEqS n k = Decision (S n :~: k)
type ListEqConsequences :: [e] -> [e] -> Type
type ListEqConsequences (xs :: [e]) (ys :: [e]) =
ElimList (ConstSym1 ([e] ~> Type)) xs
ListEqConsequencesBaseSym0
ListEqConsequencesStepSym @@ ys
type WhyListEqConsequencesSame :: [e] -> Type
type WhyListEqConsequencesSame es = ListEqConsequences es es
type WhyDecEqNil :: [e] -> Type
type WhyDecEqNil es = Decision ('[] :~: es)
type WhyDecEqCons :: e -> [e] -> [e] -> Type
type WhyDecEqCons x xs es = Decision ((x:xs) :~: es)
type WhyIntermixListEqs1 :: e -> [e] -> [e] -> e -> Type
type WhyIntermixListEqs1 x xs ys k = (x:xs) :~: (k:ys)
type WhyIntermixListEqs2 :: e -> [e] -> [e] -> Type
type WhyIntermixListEqs2 x xs k = (x:xs) :~: (x:k)
|])