1 {-# LANGUAGE ConstraintKinds #-}
2 {-# LANGUAGE DataKinds #-}
3 {-# LANGUAGE DefaultSignatures #-}
4 {-# LANGUAGE FlexibleContexts #-}
5 {-# LANGUAGE FlexibleInstances #-}
7 {-# LANGUAGE KindSignatures #-}
8 {-# LANGUAGE MultiParamTypeClasses #-}
9 {-# LANGUAGE OverloadedStrings #-}
10 {-# LANGUAGE PolyKinds #-}
11 {-# LANGUAGE Rank2Types #-}
12 {-# LANGUAGE ScopedTypeVariables #-}
13 {-# LANGUAGE StandaloneDeriving #-}
14 {-# LANGUAGE TypeFamilies #-}
15 {-# LANGUAGE TypeInType #-}
16 {-# LANGUAGE TypeOperators #-}
17 {-# LANGUAGE UndecidableInstances #-}
18 {-# OPTIONS_GHC -fno-warn-orphans #-}
19 module Language.Symantic.Compiling.Term where
21 import qualified Data.Function as Fun
22 import qualified Data.Kind as Kind
23 import Data.Kind hiding (Type)
24 import Data.Monoid ((<>))
25 import Data.Proxy (Proxy(..))
26 import Data.String (IsString)
27 import Data.Text (Text)
28 import qualified Data.Text as Text
29 import Data.Type.Equality
30 import GHC.Exts (Constraint)
31 import Prelude hiding (not)
33 import Language.Symantic.Lib.Data.Type.List
34 import Language.Symantic.Typing
35 import Language.Symantic.Interpreting
36 import Language.Symantic.Transforming.Trans
39 -- | 'TermLC' applied on a 'LamCtx_Type'.
42 (forall term. ( Sym_of_Ifaces is term
47 -- | A data type embedding a universal quantification
48 -- over an interpreter @term@
49 -- and qualified by the symantics of a term.
51 -- Moreover the term is abstracted by a 'LamCtx_Term'
52 -- built top-down at parsing time
53 -- to build a /Higher-Order Abstract Syntax/ (HOAS)
54 -- for /lambda abstractions/ ('lam').
56 -- This data type is used to keep a parsed term polymorphic enough
57 -- to stay interpretable by different interpreters.
59 -- * @(@'Sym_of_Ifaces'@ is term)@
60 -- is needed when a symantic method includes a polymorphic type
61 -- and thus calls: 'term_from'.
63 -- * @(@'Sym_of_Ifaces'@ ls term)@ and @(@'Sym_of_Ifaces'@ rs term)@
64 -- are needed to be able to write the instance:
65 -- @(@'Term_fromR'@ is ls (i ': rs) ast)@.
67 -- * @(@'Sym_Lambda'@ term)@
68 -- is needed to be able to parse partially applied functions
69 -- (when their type is knowable).
70 data TermLC ctx h is ls rs
72 (forall term. ( Sym_of_Ifaces is term
73 , Sym_of_Ifaces ls term
74 , Sym_of_Ifaces rs term
76 ) => LamCtx_Term term ctx -> term h)
79 -- | Existential 'Term', with its 'Type'.
81 = forall (h::Kind.Type). ETerm
82 (Type (Consts_of_Ifaces is) h)
85 -- | Like 'term_from' but for a term with an empty /lambda context/.
88 => ast -> Either (Error_Term is ast) (ETerm is)
90 term_from ast LamCtx_TypeZ $ \ty (TermLC te) ->
91 Right $ ETerm ty $ Term $ te LamCtx_TermZ
94 -- | Convenient type synonym wrapping 'Term_fromR'
95 -- to initiate its recursion.
96 class Term_from is ast where
97 term_from :: Term_fromT ast ctx ret is '[] is
101 , Term_fromR is '[] is ast
102 ) => Term_from is ast where
103 term_from ast ctx k =
104 case replace_var (ast_lexem ast) ctx k of
105 Left Error_Term_unsupported -> term_fromR ast ctx k
108 replace_var :: forall lc ret.
110 -> LamCtx_Type is (Lexem ast) lc
112 Type (Consts_of_Ifaces is) (h::Kind.Type)
113 -> TermLC lc h is '[] is
114 -> Either (Error_Term is ast) ret )
115 -> Either (Error_Term is ast) ret
116 replace_var name lc k' =
118 LamCtx_TypeZ -> Left $ Error_Term_unsupported
119 LamCtx_TypeS n ty _ | n == name ->
120 k' ty $ TermLC $ \(te `LamCtx_TermS` _) -> te
121 LamCtx_TypeS _n _ty lc' ->
122 replace_var name lc' $ \ty (TermLC te::TermLC lc' h is '[] is) ->
123 k' ty $ TermLC $ \(_ `LamCtx_TermS` c) -> te c
125 -- ** Type 'Term_fromT'
126 -- | Convenient type synonym defining a term parser.
127 type Term_fromT ast ctx ret is ls rs
129 -> LamCtx_Type is (Lexem ast) ctx
130 -- ^ The bound variables in scope and their types:
131 -- built top-down in the heterogeneous list @ctx@,
132 -- from the closest including /lambda abstraction/ to the farest.
134 Type (Consts_of_Ifaces is) (h::Kind.Type)
135 -> TermLC ctx h is ls rs
136 -> Either (Error_Term is ast) ret )
137 -- ^ The accumulating continuation called bottom-up.
138 -> Either (Error_Term is ast) ret
140 -- ** Class 'Term_fromR'
141 -- | Intermediate type class to construct an instance of 'Term_from'
142 -- from many instances of 'Term_fromI', one for each item of @is@.
144 -- * @is@: starting list of /term constants/.
145 -- * @ls@: done list of /term constants/.
146 -- * @rs@: remaining list of /term constants/.
147 class Term_fromR (is::[*]) (ls::[*]) (rs::[*]) ast where
148 term_fromR :: Term_fromT ast ctx ret is ls rs
149 default term_fromR :: AST ast => Term_fromT ast ctx ret is ls rs
150 term_fromR ast _ctx _k =
151 Left $ Error_Term_unknown $
152 At (Just ast) $ ast_lexem ast
154 -- | Test whether @i@ handles the work of 'Term_from' or not,
155 -- or recurse on @rs@, preserving the starting list of /term constants/,
156 -- and keeping a list of those done to construct 'TermLC'.
158 ( Term_fromI is i ast
159 , Term_fromR is (i ': ls) rs ast
160 ) => Term_fromR is ls (i ': rs) ast where
161 term_fromR ast ctx k =
162 case term_fromI ast ctx $ \ty (TermLC te
163 ::TermLC ctx h is ls (i ': rs)) ->
165 Left Error_Term_unsupported ->
166 term_fromR ast ctx $ \ty (TermLC te
167 ::TermLC ctx h is (i ': ls) rs) ->
169 ::TermLC ctx h is ls (i ': rs))
171 -- | End the recursion.
172 instance AST ast => Term_fromR is ls '[] ast
174 -- ** Class 'Term_fromI'
175 -- | Handle the work of 'Term_from' for a given /interface/ @i@,
176 -- that is: maybe it handles the given /interface/,
177 -- and if so, maybe the term can be parsed.
178 class Term_fromI (is::[*]) (i:: *) ast where
179 term_fromI :: Term_fromT ast ctx ret is ls (i ': rs)
180 term_fromI _ast _ctx _k = Left $ Error_Term_unsupported
182 -- * Type family 'Sym_of_Ifaces'
183 type family Sym_of_Ifaces (is::[*]) (term:: * -> *) :: Constraint where
184 Sym_of_Ifaces '[] term = ()
185 Sym_of_Ifaces (i ': is) term = (Sym_of_Iface i term, Sym_of_Ifaces is term)
187 -- ** Type family 'Sym_of_Iface'
188 type family Sym_of_Iface (i:: *) :: {-term-}(* -> *) -> Constraint
190 -- * Type 'Consts_of_Ifaces'
191 type Consts_of_Ifaces is = Nub (Consts_of_IfaceR is)
193 -- ** Type family 'Consts_of_IfaceR'
194 type family Consts_of_IfaceR (is::[*]) where
195 Consts_of_IfaceR '[] = '[]
196 Consts_of_IfaceR (i ': is) = Consts_of_Iface i ++ Consts_of_IfaceR is
198 -- ** Type family 'Consts_of_Iface'
199 type family Consts_of_Iface (i::k) :: [*]
200 type instance Consts_of_Iface (Proxy Enum) = Proxy Enum ': Consts_imported_by Enum
202 -- * Type 'LamCtx_Type'
203 -- | GADT for a typing context,
204 -- accumulating an @item@ at each lambda;
205 -- used to accumulate object-types (in 'Expr_From')
206 -- or host-terms (in 'HostI')
207 -- associated with the 'LamVar's in scope.
208 data LamCtx_Type (is::[*]) (name:: *) (ctx::[*]) where
209 LamCtx_TypeZ :: LamCtx_Type is name '[]
211 -> Type (Consts_of_Ifaces is) (h::Kind.Type)
212 -> LamCtx_Type is name hs
213 -> LamCtx_Type is name (h ': hs)
214 infixr 5 `LamCtx_TypeS`
216 -- ** Type 'LamVarName'
217 type LamVarName = Text
219 -- * Type 'LamCtx_Term'
220 data LamCtx_Term (term:: * -> *) (ctx::[*]) where
221 LamCtx_TermZ :: LamCtx_Term term '[]
222 LamCtx_TermS :: term h
223 -> LamCtx_Term term hs
224 -> LamCtx_Term term (h ': hs)
225 infixr 5 `LamCtx_TermS`
227 -- * Type 'Error_Term'
228 data Error_Term (is::[*]) ast
229 = Error_Term_unknown (At ast (Lexem ast))
230 | Error_Term_unsupported
231 | Error_Term_Syntax (Error_Syntax ast)
232 | Error_Term_Constraint_not_deductible (At ast (KType (Consts_of_Ifaces is) Constraint))
233 | Error_Term_Typing (At ast (Error_Type (Consts_of_Ifaces is) ast))
234 | Error_Term_Type_mismatch (At ast (EType (Consts_of_Ifaces is)))
235 (At ast (EType (Consts_of_Ifaces is)))
236 | Error_Term_Type_is_not_an_application (At ast (EType (Consts_of_Ifaces is)))
237 deriving instance (Eq ast, Eq (Lexem ast)) => Eq (Error_Term is ast)
238 deriving instance (Show ast, Show (Lexem ast), Show_Const (Consts_of_Ifaces is)) => Show (Error_Term is ast)
240 instance Lift_Error_Syntax (Error_Term is) where
241 lift_error_syntax = Error_Term_Syntax
245 -- | Check that the 'kind_of' a given 'Type's equals a given kind,
246 -- or fail with 'Error_Type_Kind_mismatch'.
249 -> At ast (Type (Consts_of_Ifaces is) (t::kt))
250 -> ((k :~: kt) -> Either (Error_Term is ast) ret)
251 -> Either (Error_Term is ast) ret
252 check_kind ast ki (At at_ty ty) k =
253 let ki_ty = kind_of ty in
254 case eq_skind ki ki_ty of
256 Nothing -> Left $ Error_Term_Typing $
258 Error_Type_Kind_mismatch
259 (At Nothing $ EKind SKiType)
260 (At at_ty $ EKind ki_ty)
262 -- | Check that a given 'Type' is a /type application/,
263 -- or fail with 'Error_Term_Type_is_not_an_application'.
265 :: ast -> Type (Consts_of_Ifaces is) (fx::kfx)
266 -> (forall kx f x. (fx :~: f x)
267 -> Type (Consts_of_Ifaces is) (f::kx -> kfx)
268 -> Type (Consts_of_Ifaces is) (x::kx)
269 -> Either (Error_Term is ast) ret)
270 -> Either (Error_Term is ast) ret
271 check_app ast ty_fx k =
273 ty_f :$ ty_x -> k Refl ty_f ty_x
274 _ -> Left $ Error_Term_Type_is_not_an_application $
275 At (Just ast) $ EType ty_fx
277 -- | Check that two given 'Type's are equal,
278 -- or fail with 'Error_Term_Type_mismatch'.
280 :: At ast (Type (Consts_of_Ifaces is) x)
281 -> At ast (Type (Consts_of_Ifaces is) y)
282 -> ((x :~: y) -> Either (Error_Term is ast) ret)
283 -> Either (Error_Term is ast) ret
284 check_type (At at_x x) (At at_y y) k =
287 Nothing -> Left $ Error_Term_Type_mismatch
291 -- | Convenient wrapper to check for a 'Type' of kind: @* -> *@.
293 :: Type (Consts_of_Ifaces is) ty
295 -> Type (Consts_of_Ifaces is) (fx:: *)
296 -> (forall x. (fx :~: ty x)
297 -> Type (Consts_of_Ifaces is) (x:: *)
298 -> Either (Error_Term is ast) ret)
299 -> Either (Error_Term is ast) ret
300 check_type1 ty ast_ta ty_ta k =
301 check_app ast_ta ty_ta $ \Refl ty_ta_t ty_ta_a ->
302 check_kind ast_ta (SKiType `SKiArrow` SKiType) (At (Just ast_ta) ty_ta_t) $ \Refl ->
303 check_type (At Nothing ty) (At (Just ast_ta) ty_ta_t) $ \Refl ->
306 -- | Convenient wrapper to check for a 'Type' of kind: @* -> * -> *@.
308 :: Type (Consts_of_Ifaces is) (ty:: * -> * -> *)
309 -> ast -> Type (Consts_of_Ifaces is) a2b
310 -> (forall a b. (a2b :~: (ty a b))
311 -> Type (Consts_of_Ifaces is) a
312 -> Type (Consts_of_Ifaces is) b
313 -> Either (Error_Term is ast) ret)
314 -> Either (Error_Term is ast) ret
315 check_type2 ty ast ty_a2b k =
316 check_app ast ty_a2b $ \Refl ty_a2b_a2 ty_a2b_b ->
317 check_app ast ty_a2b_a2 $ \Refl ty_a2b_ty ty_a2b_a ->
318 check_kind ast (SKiType `SKiArrow` SKiType `SKiArrow` SKiType) (At (Just ast) ty_a2b_ty) $ \Refl ->
319 check_type (At Nothing ty) (At (Just ast) ty_a2b_ty) $ \Refl ->
320 k Refl ty_a2b_a ty_a2b_b
322 -- | Check that a given 'Constraint' holds,
323 -- or fail with 'Error_Term_Constraint_not_deductible'.
325 :: Proj_Con (Consts_of_Ifaces is)
326 => At ast (Type (Consts_of_Ifaces is) (q::Constraint))
327 -> (Con q -> Either (Error_Term is ast) ret)
328 -> Either (Error_Term is ast) ret
329 check_constraint (At at_q q) k =
332 Nothing -> Left $ Error_Term_Constraint_not_deductible $
335 -- | Convenient wrapper to check for a 'Constraint'
336 -- over a 'Type' of kind: @* -> *@.
338 :: Proj_Con (Consts_of_Ifaces is)
339 => Type (Consts_of_Ifaces is) con
340 -> ast -> Type (Consts_of_Ifaces is) (fx:: *)
341 -> (forall f x. (fx :~: f x)
343 -> Type (Consts_of_Ifaces is) (f:: * -> *)
344 -> Type (Consts_of_Ifaces is) (x:: *)
345 -> Either (Error_Term is ast) ret)
346 -> Either (Error_Term is ast) ret
347 check_constraint1 con ast_ta ty_ta k =
348 check_app ast_ta ty_ta $ \Refl ty_ta_t ty_ta_a ->
349 check_kind ast_ta (SKiType `SKiArrow` SKiType) (At (Just ast_ta) ty_ta_t) $ \Refl ->
350 check_constraint (At (Just ast_ta) (con :$ ty_ta_t)) $ \Con ->
351 k Refl Con ty_ta_t ty_ta_a
353 -- * Class 'Sym_Lambda'
354 class Sym_Lambda term where
355 -- | /Lambda abstraction/.
356 lam :: (term arg -> term res) -> term ((->) arg res)
357 default lam :: Trans t term
358 => (t term arg -> t term res)
359 -> t term ((->) arg res)
360 lam f = trans_lift $ lam $ trans_apply . f . trans_lift
362 -- | /Lambda application/.
363 (.$) :: term ((->) arg res) -> term arg -> term res
364 default (.$) :: Trans t term
365 => t term ((->) arg res) -> t term arg -> t term res
366 (.$) f x = trans_lift (trans_apply f .$ trans_apply x)
368 -- | Convenient 'lam' and '.$' wrapper.
369 let_ :: term var -> (term var -> term res) -> term res
370 let_ x y = lam y .$ x
372 id :: term a -> term a
373 id a = lam Fun.id .$ a
375 const :: term a -> term b -> term a
376 const a b = lam (lam . Fun.const) .$ a .$ b
378 -- | /Lambda composition/.
379 (#) :: term (b -> c) -> term (a -> b) -> term (a -> c)
380 (#) f g = lam $ \a -> f .$ (g .$ a)
382 flip :: term (a -> b -> c) -> term (b -> a -> c)
383 flip f = lam $ \b -> lam $ \a -> f .$ a .$ b
388 type instance Sym_of_Iface (Proxy (->)) = Sym_Lambda
389 type instance Consts_of_Iface (Proxy (->)) = Proxy (->) ': Consts_imported_by (->)
390 type instance Consts_imported_by (->) =
397 instance Sym_Lambda HostI where
398 lam f = HostI (unHostI . f . HostI)
400 instance Sym_Lambda TextI where
401 lam f = TextI $ \p v ->
402 let p' = Precedence 1 in
403 let x = "x" <> Text.pack (show v) in
404 paren p p' $ "\\" <> x <> " -> "
405 <> unTextI (f (TextI $ \_p _v -> x)) p' (succ v)
406 -- (.$) = textI_infix "$" (Precedence 0)
407 (.$) (TextI a1) (TextI a2) =
409 let p' = precedence_App in
410 paren p p' $ a1 p' v <> " " <> a2 p' v
413 let p' = Precedence 2 in
414 let x = "x" <> Text.pack (show v) in
415 paren p p' $ "let" <> " " <> x <> " = "
416 <> unTextI e (Precedence 0) (succ v) <> " in "
417 <> unTextI (in_ (TextI $ \_p _v -> x)) p' (succ v)
418 (#) = textI_infix "." (Precedence 9)
420 const = textI_app2 "const"
421 flip = textI_app1 "flip"
422 instance (Sym_Lambda r1, Sym_Lambda r2) => Sym_Lambda (DupI r1 r2) where
423 lam f = dupI_1 lam_f `DupI` dupI_2 lam_f
425 (.$) = dupI2 (Proxy::Proxy Sym_Lambda) (.$)
427 instance Const_from Text cs => Const_from Text (Proxy (->) ': cs) where
428 const_from "(->)" k = k (ConstZ kind)
429 const_from s k = const_from s $ k . ConstS
430 instance Show_Const cs => Show_Const (Proxy (->) ': cs) where
431 show_const ConstZ{} = "(->)"
432 show_const (ConstS c) = show_const c
434 instance -- Proj_ConC (->)
436 , Proj_Consts cs (Consts_imported_by (->))
438 ) => Proj_ConC cs (Proxy (->)) where
439 proj_conC _ (TyConst q :$ (TyConst c :$ _r))
440 | Just Refl <- eq_skind (kind_of_const c) (SKiType `SKiArrow` SKiType `SKiArrow` SKiType)
441 , Just Refl <- proj_const c (Proxy::Proxy (->))
443 _ | Just Refl <- proj_const q (Proxy::Proxy Functor) -> Just Con
444 | Just Refl <- proj_const q (Proxy::Proxy Applicative) -> Just Con
445 | Just Refl <- proj_const q (Proxy::Proxy Monad) -> Just Con
447 proj_conC _ (t@(TyConst q) :$ (TyConst c :$ _a :$ b))
448 | Just Refl <- eq_skind (kind_of_const c) (SKiType `SKiArrow` SKiType `SKiArrow` SKiType)
449 , Just Refl <- proj_const c (Proxy::Proxy (->))
451 _ | Just Refl <- proj_const q (Proxy::Proxy Monoid)
452 , Just Con <- proj_con (t :$ b) -> Just Con
454 proj_conC _c _q = Nothing
455 instance -- Term_fromI (->)
457 , Lexem ast ~ LamVarName
458 , Inj_Const (Consts_of_Ifaces is) (->)
459 , Const_from (Lexem ast) (Consts_of_Ifaces is)
461 ) => Term_fromI is (Proxy (->)) ast where
462 term_fromI ast ctx k =
463 case ast_lexem ast of
465 from_ast3 ast $ \ast_name ast_ty_arg ast_body ->
466 either (Left . Error_Term_Typing . At (Just ast)) Fun.id $
467 type_from ast_ty_arg $ \ty_arg -> Right $
468 check_kind ast SKiType (At (Just ast) ty_arg) $ \Refl ->
470 (LamCtx_TypeS (ast_lexem ast_name) ty_arg ctx) $
471 \ty_res (TermLC res) ->
472 k (ty_arg ~> ty_res) $ TermLC $
474 res (arg `LamCtx_TermS` c)
476 from_ast2 ast $ \ast_lam ast_arg_actual ->
477 term_from ast_lam ctx $ \ty_lam (TermLC lam_) ->
478 term_from ast_arg_actual ctx $ \ty_arg_actual (TermLC arg_actual) ->
479 check_type2 tyFun ast_lam ty_lam $ \Refl ty_arg ty_res ->
481 (At (Just ast_lam) ty_arg)
482 (At (Just ast_arg_actual) ty_arg_actual) $ \Refl ->
484 \c -> lam_ c .$ arg_actual c
486 from_ast3 ast $ \ast_name ast_bound ast_body ->
487 term_from ast_bound ctx $ \ty_bound (TermLC bound) ->
488 term_from ast_body (LamCtx_TypeS (ast_lexem ast_name) ty_bound ctx) $
489 \ty_res (TermLC res) ->
491 \c -> let_ (bound c) $ \arg -> res (arg `LamCtx_TermS` c)
492 _ -> Left $ Error_Term_unsupported
494 -- | The '(->)' 'Type'
495 tyFun :: Inj_Const cs (->) => Type cs (->)
496 tyFun = TyConst inj_const
498 -- | The function 'Type' @(->)@,
499 -- with an infix notation more readable.
500 (~>) :: forall cs a b. Inj_Const cs (->)
501 => Type cs a -> Type cs b -> Type cs (a -> b)
502 (~>) a b = tyFun :$ a :$ b
505 syFun :: IsString a => [Syntax a] -> Syntax a
506 syFun = Syntax "(->)"
508 (.>) :: IsString a => Syntax a -> Syntax a -> Syntax a
509 a .> b = syFun [a, b]
512 syLam :: IsString a => Syntax a -> Syntax a -> Syntax a -> Syntax a
513 syLam arg ty body = Syntax "\\" [arg, ty, body]
515 syApp :: IsString a => Syntax a -> Syntax a -> Syntax a
516 syApp lam_ arg = Syntax " " [lam_, arg]
519 syLet :: IsString a => Syntax a -> Syntax a -> Syntax a -> Syntax a
520 syLet name bound body = Syntax "let" [name, bound, body]
525 -- | Parsing utility to check that the type resulting
526 -- from the application of a given type family to a given type
527 -- is within the type stack,
528 -- or raise 'Error_Term_Type_mismatch'.
530 :: forall ast is tf root ty h ret.
531 ( root ~ Root_of_Expr is
532 , ty ~ Type_Root_of_Expr is
534 , Error_Term_Lift (Error_Term (Error_of_Type ast ty) ty ast)
535 (Error_of_Expr ast root)
536 ) => Proxy tf -> Proxy is -> ast -> ty h
537 -> (ty (Host_of_Type0_Family tf h) -> Either (Error_of_Expr ast root) ret)
538 -> Either (Error_of_Expr ast root) ret
539 check_type0_family tf is ast ty k =
540 case type0_family tf ty of
542 Nothing -> Left $ error_expr is $
543 Error_Term_Type (error_type_lift $ Error_Type_No_Type_Family ast) ast