2 {-# LANGUAGE PolyKinds #-}
3 {-# LANGUAGE UndecidableInstances #-}
4 {-# OPTIONS_GHC -fno-warn-orphans #-}
5 module Language.Symantic.Compiling.Term where
7 import qualified Data.Function as Fun
8 import qualified Data.Kind as Kind
9 import Data.Monoid ((<>))
10 import Data.Proxy (Proxy(..))
11 import Data.Text (Text)
12 import qualified Data.Text as Text
13 import Data.Type.Equality ((:~:)(..))
14 import GHC.Exts (Constraint)
15 import Prelude hiding (not)
17 import Language.Symantic.Lib.Data.Type.List
18 import Language.Symantic.Parsing
19 import Language.Symantic.Typing
20 import Language.Symantic.Interpreting
21 import Language.Symantic.Transforming.Trans
27 (forall term. ( Sym_of_Ifaces is term
32 -- | An open term (i.e. with a /lambda context/).
33 -- The data type wraps a universal quantification
34 -- over an interpreter @term@
35 -- qualified by the symantics of a term.
37 -- Moreover the term is abstracted by a 'LamCtx_Term'
38 -- built top-down at by 'compileO'
39 -- to build a /Higher-Order Abstract Syntax/ (HOAS)
40 -- for /lambda abstractions/ ('lam').
42 -- This data type is used to keep a parsed term polymorphic enough
43 -- to stay interpretable by different interpreters.
45 -- * @(@'Sym_of_Ifaces'@ is term)@
46 -- is needed when a symantic method includes a polymorphic type
47 -- and thus calls: 'compileO'.
49 -- * @(@'Sym_of_Ifaces'@ ls term)@ and @(@'Sym_of_Ifaces'@ rs term)@
50 -- make a zipper needed to be able to write the recursing 'CompileR' instance.
52 -- * @(@'Sym_Lambda'@ term)@
53 -- is needed to handle partially applied functions.
54 data TermO ctx h is ls rs
56 (forall term. ( Sym_of_Ifaces is term
57 , Sym_of_Ifaces ls term
58 , Sym_of_Ifaces rs term
60 ) => LamCtx_Term term ctx -> term h)
63 -- | Existential 'Term', with its 'Type'.
65 = forall (h::Kind.Type). ETerm
66 (Type (Consts_of_Ifaces is) h)
70 -- | Convenient type synonym wrapping 'CompileR' to initiate its recursion.
71 class Compile is where
72 compileO :: EToken meta is -> CompileT meta ctx ret is '[] is
73 instance CompileR is '[] is => Compile is where
74 compileO (EToken tok) = compileR tok
76 -- | Like 'compileO' but for a term with an empty /lambda context/.
80 -> Either (Error_Term meta is) (ETerm is)
82 compileO tok LamCtx_TypeZ $ \typ (TermO te) ->
83 Right $ ETerm typ $ Term $ te LamCtx_TermZ
86 -- | Convenient type synonym defining a term parser.
87 type CompileT meta ctx ret is ls rs
88 = LamCtx_Type is Name_LamVar ctx
89 -- ^ The bound variables in scope and their types:
90 -- built top-down in the heterogeneous list @ctx@,
91 -- from the closest including /lambda abstraction/ to the farest.
93 Type (Consts_of_Ifaces is) (h::Kind.Type)
94 -> TermO ctx h is ls rs
95 -> Either (Error_Term meta is) ret )
96 -- ^ The accumulating continuation called bottom-up.
97 -> Either (Error_Term meta is) ret
99 -- ** Class 'CompileR'
100 -- | Intermediate type class to construct an instance of 'Compile'
101 -- from many instances of 'CompileI', one for each item of @is@.
103 -- * @is@: starting list of /term constants/.
104 -- * @ls@: done list of /term constants/.
105 -- * @rs@: remaining list of /term constants/.
106 class CompileR (is::[*]) (ls::[*]) (rs::[*]) where
107 compileR :: TokenR meta is rs i -> CompileT meta ctx ret is ls rs
109 -- | Recurse into into the given 'TokenR'
110 -- to call the 'compileI' instance associated
111 -- to the 'TokenT' it contains.
114 , CompileR is (i ': ls) (r ': rs)
115 ) => CompileR is ls (i ': r ': rs) where
118 TokenZ _m t -> compileI t ctx k
120 compileR t ctx $ \typ (TermO te :: TermO ctx h is (i ': ls) (r ': rs)) ->
121 k typ (TermO te :: TermO ctx h is ls (i ': r ': rs))
122 -- | End the recursion.
125 CompileR is ls (i ': '[]) where
126 compileR (TokenZ _m t) ctx k = compileI t ctx k
127 compileR TokenS{} _ctx _k = error "Oops, the impossible happened..."
129 -- ** Class 'CompileI'
130 -- | Handle the work of 'Compile' for a given /interface/ @i@.
131 class CompileI (is::[*]) (i:: *) where
132 compileI :: TokenT meta is i -> CompileT meta ctx ret is ls (i ': rs)
134 -- * Type family 'Sym_of_Ifaces'
135 type family Sym_of_Ifaces (is::[*]) (term:: * -> *) :: Constraint where
136 Sym_of_Ifaces '[] term = ()
137 Sym_of_Ifaces (i ': is) term = (Sym_of_Iface i term, Sym_of_Ifaces is term)
139 -- ** Type family 'Sym_of_Iface'
140 type family Sym_of_Iface (i:: *) :: {-term-}(* -> *) -> Constraint
142 -- * Type 'Consts_of_Ifaces'
143 type Consts_of_Ifaces is = Nub (Consts_of_IfaceR is)
145 -- ** Type family 'Consts_of_IfaceR'
146 type family Consts_of_IfaceR (is::[*]) where
147 Consts_of_IfaceR '[] = '[]
148 Consts_of_IfaceR (i ': is) = Consts_of_Iface i ++ Consts_of_IfaceR is
150 -- ** Type family 'Consts_of_Iface'
151 type family Consts_of_Iface (i:: *) :: [*]
152 type instance Consts_of_Iface (Proxy Enum) = Proxy Enum ': Consts_imported_by Enum
154 -- * Type 'LamCtx_Type'
155 -- | GADT for a typing context,
156 -- accumulating an @item@ at each lambda;
157 -- used to accumulate object-types (in 'Expr_From')
158 -- or host-terms (in 'HostI')
159 -- associated with the 'LamVar's in scope.
160 data LamCtx_Type (is::[*]) (name:: *) (ctx::[*]) where
161 LamCtx_TypeZ :: LamCtx_Type is name '[]
163 -> Type (Consts_of_Ifaces is) (h::Kind.Type)
164 -> LamCtx_Type is name hs
165 -> LamCtx_Type is name (h ': hs)
166 infixr 5 `LamCtx_TypeS`
168 -- ** Type 'Name_LamVar'
169 type Name_LamVar = Text
171 -- * Type 'LamCtx_Term'
172 data LamCtx_Term (term:: * -> *) (ctx::[*]) where
173 LamCtx_TermZ :: LamCtx_Term term '[]
174 LamCtx_TermS :: term h
175 -> LamCtx_Term term hs
176 -> LamCtx_Term term (h ': hs)
177 infixr 5 `LamCtx_TermS`
179 -- * Type 'Error_Term'
180 data Error_Term meta (is::[*])
181 = Error_Term_unbound Name_LamVar
182 | Error_Term_Typing (Error_Type meta '[Proxy Token_Type])
183 | Error_Term_Constraint_Type
185 (Constraint_Type meta '[Proxy Token_Type] (Consts_of_Ifaces is))
186 (Constraint_Type meta is (Consts_of_Ifaces is)))
187 | Error_Term_Constraint_Kind (Constraint_Kind meta is)
188 deriving instance (Eq meta, Eq_Token meta is) => Eq (Error_Term meta is)
189 deriving instance (Show meta, Show_Token meta is, Show_Const (Consts_of_Ifaces is)) => Show (Error_Term meta is)
191 -- * Type 'Constraint_Type'
192 data Constraint_Type meta ts cs
193 = Constraint_Type_Eq (Either (At meta '[Proxy Token_Type] (EType cs))
194 (At meta ts (EType cs)))
195 (At meta ts (EType cs))
196 | Constraint_Type_App (At meta ts (EType cs))
197 | Constraint_Type_Con (At meta ts (KType cs Constraint))
198 | Constraint_Type_Fam (At meta ts Name_Fam) [EType cs]
202 ) => Eq (Constraint_Type meta ts cs)
207 ) => Show (Constraint_Type meta ts cs)
210 instance MonoLift (Error_Type meta '[Proxy Token_Type]) (Error_Term meta ts) where
211 olift = Error_Term_Typing . olift
212 instance MonoLift (Error_Term meta ts) (Error_Term meta ts) where
215 cs ~ Consts_of_Ifaces is =>
216 MonoLift (Constraint_Type meta is cs) (Error_Term meta is) where
217 olift = Error_Term_Constraint_Type . Right
219 cs ~ Consts_of_Ifaces is =>
220 MonoLift (Constraint_Type meta '[Proxy Token_Type] cs) (Error_Term meta is) where
221 olift = Error_Term_Constraint_Type . Left
222 instance MonoLift (Constraint_Kind meta '[Proxy Token_Type]) (Error_Term meta is) where
223 olift = Error_Term_Typing . Error_Type_Constraint_Kind
224 instance MonoLift (Constraint_Kind meta is) (Error_Term meta is) where
225 olift = Error_Term_Constraint_Kind
229 :: MonoLift (Constraint_Type meta ts cs) err
230 => At meta ts (Type cs x)
231 -> At meta ts (Type cs y)
232 -> ((x :~: y) -> Either err ret) -> Either err ret
234 case unAt x `eq_type` unAt y of
236 Nothing -> Left $ olift $
237 Constraint_Type_Eq (Right $ EType <$> x) (EType <$> y)
240 :: MonoLift (Constraint_Type meta ts cs) err
241 => At meta '[Proxy Token_Type] (Type cs x)
242 -> At meta ts (Type cs y)
243 -> ((x :~: y) -> Either err ret) -> Either err ret
244 check_type_is x y k =
245 case unAt x `eq_type` unAt y of
247 Nothing -> Left $ olift $
248 Constraint_Type_Eq (Left $ EType <$> x) (EType <$> y)
251 :: MonoLift (Constraint_Type meta ts cs) err
252 => At meta ts (Type cs (fa::kfa))
253 -> (forall ka f a. (fa :~: f a)
254 -> Type cs (f::ka -> kfa)
258 check_type_app typ k =
262 Constraint_Type_App (EType <$> typ)
265 :: ( MonoLift (Constraint_Type meta ts cs) err
266 , MonoLift (Constraint_Kind meta ts) err )
267 => Type cs (f:: * -> *)
268 -> At meta ts (Type cs fa)
269 -> (forall a. (fa :~: f a)
273 check_type1 typ ty_fa k =
274 check_type_app ty_fa $ \Refl ty_f ty_a ->
276 (At Nothing $ SKiType `SKiArrow` SKiType)
277 (kind_of ty_f <$ ty_fa) $ \Refl ->
280 (ty_f <$ ty_fa) $ \Refl ->
284 :: ( MonoLift (Constraint_Type meta ts cs) err
285 , MonoLift (Constraint_Kind meta ts) err )
286 => Type cs (f:: * -> * -> *)
287 -> At meta ts (Type cs fab)
288 -> (forall a b. (fab :~: f a b)
293 check_type2 typ ty_fab k =
294 check_type_app ty_fab $ \Refl ty_fa ty_b ->
295 check_type_app (ty_fa <$ ty_fab) $ \Refl ty_f ty_a ->
297 (At Nothing $ SKiType `SKiArrow` SKiType `SKiArrow` SKiType)
298 (kind_of ty_f <$ ty_fab) $ \Refl ->
301 (ty_f <$ ty_fab) $ \Refl ->
306 , MonoLift (Constraint_Type meta ts cs) err )
307 => At meta ts (Type cs (q::Constraint))
308 -> (Con q -> Either err ret)
311 case proj_con $ unAt typ of
313 Nothing -> Left $ olift $
314 Constraint_Type_Con (KType <$> typ)
318 , MonoLift (Constraint_Type meta ts cs) err
319 , MonoLift (Constraint_Kind meta ts) err )
321 -> At meta ts (Type cs (fa:: *))
322 -> (forall f a. (fa :~: f a)
324 -> Type cs (f:: * -> *)
328 check_con1 con ty_fa k =
329 check_type_app ty_fa $ \Refl ty_f ty_a ->
331 (At Nothing (SKiType `SKiArrow` SKiType))
332 (kind_of ty_f <$ ty_fa) $ \Refl ->
333 check_con ((con :$ ty_f) <$ ty_fa) $ \Con ->
337 :: ( MonoLift (Constraint_Type meta ts cs) err
342 -> (Type cs (Fam fam hs) -> Either err ret)
344 check_fam fam tys k =
345 case proj_fam (unAt fam) tys of
347 Nothing -> Left $ olift $
349 (Text.pack . show <$> fam)
352 -- * Class 'Sym_Lambda'
353 class Sym_Lambda term where
354 -- | /Lambda abstraction/.
355 lam :: (term arg -> term res) -> term ((->) arg res)
356 default lam :: Trans t term
357 => (t term arg -> t term res)
358 -> t term ((->) arg res)
359 lam f = trans_lift $ lam $ trans_apply . f . trans_lift
361 -- | /Lambda application/.
362 (.$) :: term ((->) arg res) -> term arg -> term res
363 default (.$) :: Trans t term
364 => t term ((->) arg res) -> t term arg -> t term res
365 (.$) f x = trans_lift (trans_apply f .$ trans_apply x)
367 -- | Convenient 'lam' and '.$' wrapper.
368 let_ :: term var -> (term var -> term res) -> term res
369 let_ x y = lam y .$ x
371 id :: term a -> term a
372 id a = lam Fun.id .$ a
374 const :: term a -> term b -> term a
375 const a b = lam (lam . Fun.const) .$ a .$ b
377 -- | /Lambda composition/.
378 (#) :: term (b -> c) -> term (a -> b) -> term (a -> c)
379 (#) f g = lam $ \a -> f .$ (g .$ a)
381 flip :: term (a -> b -> c) -> term (b -> a -> c)
382 flip f = lam $ \b -> lam $ \a -> f .$ a .$ b
387 type instance Sym_of_Iface (Proxy (->)) = Sym_Lambda
388 type instance Consts_of_Iface (Proxy (->)) = Proxy (->) ': Consts_imported_by (->)
389 type instance Consts_imported_by (->) =
396 instance Sym_Lambda HostI where
397 lam f = HostI (unHostI . f . HostI)
399 instance Sym_Lambda TextI where
400 lam f = TextI $ \p v ->
401 let p' = Precedence 1 in
402 let x = "x" <> Text.pack (show v) in
403 paren p p' $ "\\" <> x <> " -> "
404 <> unTextI (f (TextI $ \_p _v -> x)) p' (succ v)
405 -- (.$) = textI_infix "$" (Precedence 0)
406 (.$) (TextI a1) (TextI a2) =
408 let p' = precedence_App in
409 paren p p' $ a1 p' v <> " " <> a2 p' v
412 let p' = Precedence 2 in
413 let x = "x" <> Text.pack (show v) in
414 paren p p' $ "let" <> " " <> x <> " = "
415 <> unTextI e (Precedence 0) (succ v) <> " in "
416 <> unTextI (in_ (TextI $ \_p _v -> x)) p' (succ v)
417 (#) = textI_infix "." (Precedence 9)
419 const = textI_app2 "const"
420 flip = textI_app1 "flip"
421 instance (Sym_Lambda r1, Sym_Lambda r2) => Sym_Lambda (DupI r1 r2) where
422 lam f = dupI_1 lam_f `DupI` dupI_2 lam_f
424 (.$) = dupI2 (Proxy::Proxy Sym_Lambda) (.$)
426 instance Const_from Text cs => Const_from Text (Proxy (->) ': cs) where
427 const_from "(->)" k = k (ConstZ kind)
428 const_from s k = const_from s $ k . ConstS
429 instance Show_Const cs => Show_Const (Proxy (->) ': cs) where
430 show_const ConstZ{} = "(->)"
431 show_const (ConstS c) = show_const c
433 instance -- Proj_ConC (->)
435 , Proj_Consts cs (Consts_imported_by (->))
437 ) => Proj_ConC cs (Proxy (->)) where
438 proj_conC _ (TyConst q :$ (TyConst c :$ _r))
439 | Just Refl <- eq_skind (kind_of_const c) (SKiType `SKiArrow` SKiType `SKiArrow` SKiType)
440 , Just Refl <- proj_const c (Proxy::Proxy (->))
442 _ | Just Refl <- proj_const q (Proxy::Proxy Functor) -> Just Con
443 | Just Refl <- proj_const q (Proxy::Proxy Applicative) -> Just Con
444 | Just Refl <- proj_const q (Proxy::Proxy Monad) -> Just Con
446 proj_conC _ (t@(TyConst q) :$ (TyConst c :$ _a :$ b))
447 | Just Refl <- eq_skind (kind_of_const c) (SKiType `SKiArrow` SKiType `SKiArrow` SKiType)
448 , Just Refl <- proj_const c (Proxy::Proxy (->))
450 _ | Just Refl <- proj_const q (Proxy::Proxy Monoid)
451 , Just Con <- proj_con (t :$ b) -> Just Con
453 proj_conC _c _q = Nothing
454 data instance TokenT meta (ts::[*]) (Proxy (->))
455 = Token_Term_Abst Name_LamVar (EToken meta '[Proxy Token_Type]) (EToken meta ts)
456 | Token_Term_App (EToken meta ts) (EToken meta ts)
457 | Token_Term_Let Name_LamVar (EToken meta ts) (EToken meta ts)
458 | Token_Term_Var Name_LamVar
459 deriving instance (Eq meta, Eq_Token meta ts) => Eq (TokenT meta ts (Proxy (->)))
460 deriving instance (Show meta, Show_Token meta ts) => Show (TokenT meta ts (Proxy (->)))
461 instance -- CompileI (->)
462 ( Inj_Const (Consts_of_Ifaces is) (->)
463 , Const_from Name_LamVar (Consts_of_Ifaces is)
465 ) => CompileI is (Proxy (->)) where
468 Token_Term_Abst name_arg tok_ty_arg tok_body ->
469 type_from tok_ty_arg $ \(ty_arg::Type (Consts_of_Ifaces is) h) ->
472 (At (Just $ tok_ty_arg) $ kind_of ty_arg) $ \Refl ->
474 (LamCtx_TypeS name_arg ty_arg ctx) $
475 \ty_res (TermO res) ->
476 k (ty_arg ~> ty_res) $ TermO $
478 res (arg `LamCtx_TermS` c)
479 Token_Term_App tok_lam tok_arg_actual ->
480 compileO tok_lam ctx $ \ty_lam (TermO lam_) ->
481 compileO tok_arg_actual ctx $ \ty_arg_actual (TermO arg_actual) ->
482 check_type2 (ty @(->)) (At (Just tok_lam) ty_lam) $ \Refl ty_arg ty_res ->
484 (At (Just tok_lam) ty_arg)
485 (At (Just tok_arg_actual) ty_arg_actual) $ \Refl ->
487 \c -> lam_ c .$ arg_actual c
488 Token_Term_Let name tok_bound tok_body ->
489 compileO tok_bound ctx $ \ty_bound (TermO bound) ->
490 compileO tok_body (LamCtx_TypeS name ty_bound ctx) $
491 \ty_res (TermO res) ->
493 \c -> let_ (bound c) $ \arg -> res (arg `LamCtx_TermS` c)
494 Token_Term_Var nam -> go nam ctx k
496 go :: forall meta lc ret ls rs.
498 -> LamCtx_Type is Name_LamVar lc
500 Type (Consts_of_Ifaces is) (h::Kind.Type)
501 -> TermO lc h is ls rs
502 -> Either (Error_Term meta is) ret )
503 -> Either (Error_Term meta is) ret
506 LamCtx_TypeZ -> Left $ Error_Term_unbound name
507 LamCtx_TypeS n typ _ | n == name ->
508 k' typ $ TermO $ \(te `LamCtx_TermS` _) -> te
509 LamCtx_TypeS _n _ty lc' ->
510 go name lc' $ \typ (TermO te::TermO lc' h is '[] is) ->
511 k' typ $ TermO $ \(_ `LamCtx_TermS` c) -> te c
513 -- | The function 'Type' @(->)@,
514 -- with an infix notation more readable.
515 (~>) :: forall cs a b. Inj_Const cs (->)
516 => Type cs a -> Type cs b -> Type cs (a -> b)
517 (~>) a b = ty @(->) :$ a :$ b
521 -- * Class 'Sym_Type'
523 instance Sym_Type term
524 type instance Sym_of_Iface (Proxy Token_Type) = Sym_Type
525 type instance Consts_of_Iface (Proxy Token_Type) = '[]
526 type instance Consts_imported_by Token_Type = '[]
527 instance -- Proj_ConC
528 Proj_ConC cs (Proxy Token_Type)
529 instance -- CompileI (->)
530 CompileI is (Proxy Token_Type) where
531 compileI _tok _ctx _k = Left $ Error_Term_unbound