2 {-# LANGUAGE TypeInType #-}
3 module Language.Symantic.Typing.Constant where
5 import qualified Data.Kind as Kind
6 import qualified Data.Map.Strict as Map
7 import qualified Data.MonoTraversable as MT
8 import qualified Data.Sequences as Seqs
9 import Data.NonNull (NonNull)
11 import Data.Text (Text)
12 import Data.Type.Equality
13 import GHC.Exts (Constraint)
14 import qualified System.IO as IO
16 import Language.Symantic.Lib.Data.Type.List
17 import Language.Symantic.Lib.Data.Type.Peano
18 import Language.Symantic.Typing.Kind
21 -- | A /type constant/,
22 -- indexed at the Haskell type and term level amongst a list of them.
23 -- When used, @c@ is actually wrapped within a 'Proxy'
24 -- to be able to handle constants of different 'Kind's.
25 data Const (cs::[Kind.Type]) (c::k) where
26 ConstZ :: SKind k -> Const (Proxy c ': cs) (c::k)
27 ConstS :: Const cs c -> Const (not_c ': cs) c
30 eq_kind_const :: Const cs (x::kx) -> Const cs (y::ky) -> Maybe (kx:~:ky)
31 eq_kind_const x y = eq_skind (kind_of_const x) (kind_of_const y)
33 instance TestEquality (Const cs) where
34 testEquality ConstZ{} ConstZ{} = Just Refl
35 testEquality (ConstS x) (ConstS y) = testEquality x y
36 testEquality _ _ = Nothing
38 kind_of_const :: Const cs (h::k) -> SKind k
39 kind_of_const (ConstZ ki) = ki
40 kind_of_const (ConstS c) = kind_of_const c
43 -- | Convenient type synonym wrapping 'Inj_ConstP'
44 -- applied on the correct 'Index'.
45 type Inj_Const cs c = Inj_ConstP (Index cs (Proxy c)) cs c
47 -- | Inject a given /type constant/ @c@ into a list of them,
48 -- by returning a proof that 'Proxy'@ c@ is in @cs@.
49 inj_const :: forall cs c. Inj_Const cs c => Const cs c
50 inj_const = inj_constP (Proxy::Proxy (Index cs (Proxy c)))
52 -- ** Class 'Inj_ConstP'
53 class Inj_ConstP p cs c where
54 inj_constP :: Proxy p -> Const cs c
55 {- NOTE: using this commented instance fails very badly due to GHC-8.0.1's bug #12933
56 which makes it fail to calculate the right kind,
57 it seems to wrongly reuse the kind of the first use (sic)…
58 instance IKind k => Inj_ConstP Zero (Proxy c ': cs) (c::k) where
59 inj_constP _ = ConstZ kind
62 ( IKindP (Ty_of_Type k)
63 , Type_of_Ty (Ty_of_Type k) ~ k
64 ) => Inj_ConstP Zero (Proxy c ': cs) (c::k) where
65 inj_constP _ = ConstZ (kindP (Proxy :: Proxy (Ty_of_Type k)))
66 instance Inj_ConstP p cs c => Inj_ConstP (Succ p) (not_c ': cs) c where
67 inj_constP _p = ConstS (inj_constP (Proxy::Proxy p))
69 -- * Class 'Proj_Const'
70 -- | Convenient type synonym wrapping 'Proj_ConstP'
71 -- applied on the correct 'Index'.
72 type Proj_Const cs c = Proj_ConstP (Index cs (Proxy c)) cs c
74 -- | Project a 'Const' onto a Haskell type level /type constant/ @c@,
75 -- returning a proof that the 'Const' indexes @c@ iif. it's the case.
76 proj_const :: forall cs k (c::k) (u::k).
77 Proj_Const cs c => Const cs u -> Proxy c -> Maybe (c :~: u)
78 proj_const = proj_constP (Proxy::Proxy (Index cs (Proxy c)))
80 (=?) :: forall cs c u. Proj_Const cs c => Const cs u -> Proxy c -> Maybe (c :~: u)
81 (=?) = proj_constP (Proxy::Proxy (Index cs (Proxy c)))
83 -- ** Type 'Proj_ConstP'
84 class Proj_ConstP p cs c where
85 proj_constP :: Proxy p -> Const cs u -> Proxy c -> Maybe (c :~: u)
86 instance Proj_ConstP Zero (Proxy c ': cs) c where
87 proj_constP _p ConstZ{} _c = Just Refl
88 proj_constP _p ConstS{} _c = Nothing
89 instance Proj_ConstP p cs c => Proj_ConstP (Succ p) (not_c ': cs) c where
90 proj_constP _p ConstZ{} _c = Nothing
91 proj_constP _p (ConstS u) c = proj_constP (Proxy::Proxy p) u c
93 -- ** Type 'Proj_Consts'
94 type Proj_Consts cs cs_to_proj
95 = Concat_Constraints (Proj_ConstsR cs cs_to_proj)
97 -- *** Type family 'Proj_ConstsR'
98 type family Proj_ConstsR cs cs_to_proj :: [Constraint] where
99 Proj_ConstsR cs '[] = '[]
100 Proj_ConstsR cs (Proxy x ': xs) = Proj_Const cs x ': Proj_ConstsR cs xs
102 -- * Class 'Const_from'
103 -- | Try to build a 'Const' from raw data.
104 class Const_from raw cs where
106 :: raw -> (forall k c. Const cs (c::k) -> Maybe ret)
109 instance Const_from raw '[] where
110 const_from _c _k = Nothing
112 -- TODO: move each of these to a dedicated module.
113 instance Const_from Text cs => Const_from Text (Proxy Bounded ': cs) where
114 const_from "Bounded" k = k (ConstZ kind)
115 const_from s k = const_from s $ k . ConstS
116 instance Const_from Text cs => Const_from Text (Proxy Enum ': cs) where
117 const_from "Enum" k = k (ConstZ kind)
118 const_from s k = const_from s $ k . ConstS
119 instance Const_from Text cs => Const_from Text (Proxy Fractional ': cs) where
120 const_from "Fractional" k = k (ConstZ kind)
121 const_from s k = const_from s $ k . ConstS
122 instance Const_from Text cs => Const_from Text (Proxy Real ': cs) where
123 const_from "Real" k = k (ConstZ kind)
124 const_from s k = const_from s $ k . ConstS
126 -- * Class 'Show_Const'
127 class Show_Const cs where
128 show_const :: Const cs c -> String
130 -- deriving instance Show (Const cs c)
131 instance Show_Const cs => Show (Const cs c) where
133 instance Show_Const '[] where
134 show_const = error "Show_Const unreachable pattern"
136 -- TODO: move each of these to a dedicated module.
137 instance Show_Const cs => Show_Const (Proxy Bounded ': cs) where
138 show_const ConstZ{} = "Bounded"
139 show_const (ConstS c) = show_const c
140 instance Show_Const cs => Show_Const (Proxy Enum ': cs) where
141 show_const ConstZ{} = "Enum"
142 show_const (ConstS c) = show_const c
143 instance Show_Const cs => Show_Const (Proxy Fractional ': cs) where
144 show_const ConstZ{} = "Fractional"
145 show_const (ConstS c) = show_const c
146 instance Show_Const cs => Show_Const (Proxy Real ': cs) where
147 show_const ConstZ{} = "Real"
148 show_const (ConstS c) = show_const c
150 -- * Type 'Constants'
152 type Constants = Terms ++ Constraints
155 -- | Usual 'Const's of /terms constructors/.
176 -- ** Type 'Constraints'
177 -- | Usual 'Const's of /type constraint constructors/.
187 , Proxy MT.MonoFoldable
188 , Proxy MT.MonoFunctor
192 , Proxy Seqs.IsSequence
193 , Proxy Seqs.SemiSequence