Bump versions.
[haskell/symantic.git] / symantic / Language / Symantic / Compiling / Term.hs
index 0c7006b5099fa405ad525298740c16784f9595e2..1dc2b8ce7ac24cf9ed0cdb06248270d6287ddf18 100644 (file)
+{-# LANGUAGE AllowAmbiguousTypes #-}
 {-# LANGUAGE ConstraintKinds #-}
+{-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE GADTs #-}
-{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE TypeInType #-}
 {-# LANGUAGE UndecidableInstances #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
-module Language.Symantic.Compiling.Term
- ( module Language.Symantic.Compiling.Term
- , module Language.Symantic.Compiling.Term.Grammar
- ) where
+module Language.Symantic.Compiling.Term where
 
-import qualified Data.Kind as Kind
-import Data.Proxy (Proxy(..))
+import Data.Maybe (isJust)
+import Data.Semigroup (Semigroup(..))
+import qualified Data.Kind as K
+import qualified Data.Set as Set
 import qualified Data.Text as Text
-import Data.Type.Equality ((:~:)(..))
-import GHC.Exts (Constraint)
 
-import Language.Symantic.Helper.Data.Type.List
-import Language.Symantic.Parsing
+import Language.Symantic.Grammar
+import Language.Symantic.Interpreting
+import Language.Symantic.Transforming.Trans
 import Language.Symantic.Typing
 
-import Language.Symantic.Compiling.Term.Grammar
-
 -- * Type 'Term'
--- | Closed 'TermO'.
-data Term is h
- =   Term
- (forall term. ( Sym_of_Ifaces is term
-               , Sym_of_Iface (Proxy (->)) term
-               ) => term h)
-
--- ** Type 'TermO'
--- | An open term (i.e. with a /lambda context/).
--- The data type wraps a universal quantification
--- over an interpreter @term@
--- qualified by the symantics of a term.
---
--- Moreover the term is abstracted by a 'LamCtx_Term'
--- built top-down by 'compileO',
--- to enable a /Higher-Order Abstract Syntax/ (HOAS)
--- for /lambda abstractions/ ('lam').
---
--- This data type is used to keep a parsed term polymorphic enough
--- to stay interpretable by different interpreters.
---
--- * @(@'Sym_of_Ifaces'@ is term)@
--- is needed when a symantic method includes a polymorphic type
--- and thus calls: 'compileO'.
---
--- * @(@'Sym_of_Ifaces'@ ls term)@ and @(@'Sym_of_Ifaces'@ rs term)@
--- make a zipper needed to be able to write the recursing 'CompileR' instance.
---
--- * @(@'Sym_of_Iface'@ (@'Proxy'@ (->)) term)@
--- is needed to handle partially applied functions.
-data TermO ctx h is ls rs
- =   TermO
- (forall term. ( Sym_of_Ifaces is term
-               , Sym_of_Ifaces ls term
-               , Sym_of_Ifaces rs term
-               , Sym_of_Iface (Proxy (->)) term
-               ) => LamCtx_Term term ctx -> term h)
-
--- * Type 'ETerm'
--- | Existential 'Term', with its 'Type'.
-data ETerm is
- = forall (h::Kind.Type). ETerm
-   (Type (TyConsts_of_Ifaces is) h)
-   (Term is h)
+data Term src ss ts vs (t::K.Type)
+ =   Term (Type src vs (QualOf t))
+          (Type src vs (UnQualOf t))
+          (TeSym ss ts t)
+instance Source src => Eq (Term src ss ts vs t) where
+       Term qx tx _ == Term qy ty _ = qx == qy && tx == ty
+instance Source src => Show (Term src ss ts vs t) where
+       showsPrec p (Term q t _te) = showsPrec p (q #> t)
 
--- * Type 'Compile'
--- | Convenient type synonym wrapping 'CompileR' to initiate its recursion.
-class Compile is where
-       compileO :: EToken meta is -> CompileT meta ctx ret is '[] is
-instance CompileR is '[] is => Compile is where
-       compileO (EToken tok) = compileR tok
+-- Source
+type instance SourceOf (Term src ss ts vs t) = src
+instance Source src => Sourced (Term src ss ts vs t) where
+       sourceOf  (Term _q t _te)    = sourceOf t
+       setSource (Term q t te) src = Term q (setSource t src) te
 
--- | Like 'compileO' but for a term with an empty /lambda context/.
-compile
- :: Compile is
- => EToken meta is
- -> Either (Error_Term meta is) (ETerm is)
-compile tok =
-       compileO tok LamCtx_TypeZ $ \typ (TermO te) ->
-       Right $ ETerm typ $ Term $ te LamCtx_TermZ
+-- Const
+instance ConstsOf (Term src ss ts vs t) where
+       constsOf (Term q t _te) = constsOf q `Set.union` constsOf t
 
--- ** Type 'CompileT'
--- | Convenient type synonym defining a term parser.
-type CompileT meta ctx ret is ls rs
- = LamCtx_Type is Term_Name ctx
- -- ^ The bound variables in scope and their types:
- -- built top-down in the heterogeneous list @ctx@,
- -- from the closest including /lambda abstraction/ to the farest.
- -> ( forall h.
-       Type (TyConsts_of_Ifaces is) (h::Kind.Type)
-    -> TermO ctx h is ls rs
-    -> Either (Error_Term meta is) ret )
- -- ^ The accumulating continuation called bottom-up.
- -> Either (Error_Term meta is) ret
+-- Var
+type instance VarsOf (Term src ss ts vs t) = vs
+instance LenVars (Term src ss ts vs t) where
+       lenVars (Term _q t _te) = lenVars t
+instance AllocVars (Term src ss ts) where
+       allocVarsL len (Term q t te) = Term (allocVarsL len q) (allocVarsL len t) te
+       allocVarsR len (Term q t te) = Term (allocVarsR len q) (allocVarsR len t) te
 
--- ** Class 'CompileR'
--- | Intermediate type class to construct an instance of 'Compile'
--- from many instances of 'CompileI', one for each item of @is@.
---
--- * @is@: starting  list of /term constants/.
--- * @ls@: done      list of /term constants/.
--- * @rs@: remaining list of /term constants/.
-class CompileR (is::[*]) (ls::[*]) (rs::[*]) where
-       compileR :: TokenR meta is rs i -> CompileT meta ctx ret is ls rs
+-- Fam
+instance ExpandFam (Term src ss ts vs t) where
+       expandFam (Term q t te) = Term (expandFam q) (expandFam t) te
 
--- | Recurse into into the given 'TokenR'
--- to call the 'compileI' instance associated
--- to the 'TokenT' it contains.
-instance
- ( CompileI is i
- , CompileR is (i ': ls) (r ': rs)
- ) => CompileR is ls (i ': r ': rs) where
-       compileR tok ctx k =
-               case tok of
-                TokenZ _m t -> compileI t ctx k
-                TokenS t ->
-                       compileR t ctx $ \typ (TermO te :: TermO ctx h is (i ': ls) (r ': rs)) ->
-                               k typ (TermO te :: TermO ctx h is ls (i ': r ': rs))
--- | End the recursion.
-instance
- CompileI is i =>
- CompileR is ls (i ': '[]) where
-       compileR (TokenZ _m t) ctx k = compileI t ctx k
-       compileR TokenS{} _ctx _k = error "Oops, the impossible happened..."
+-- ** Type 'TermT'
+-- | 'Term' with existentialized 'Type'.
+data TermT src ss ts vs = forall t. TermT (Term src ss ts vs t)
+instance Source src => Show (TermT src ss ts vs) where
+       showsPrec p (TermT t) = showsPrec p t
 
--- ** Class 'CompileI'
--- | Handle the work of 'Compile' for a given /interface/ @i@.
-class CompileI (is::[*]) (i:: *) where
-       compileI :: TokenT meta is i -> CompileT meta ctx ret is ls (i ': rs)
+-- ** Type 'TermVT'
+-- | 'Term' with existentialized 'Var's and 'Type'.
+data TermVT src ss ts = forall vs t. TermVT (Term src ss ts vs t)
+instance Source src => Eq (TermVT src ss ts) where
+       TermVT x == TermVT y =
+               let (Term qx' tx' _, Term qy' ty' _) = appendVars x y in
+               isJust $ (qx' #> tx') `eqTypeKi` (qy' #> ty')
+instance Source src => Show (TermVT src ss ts) where
+       showsPrec p (TermVT t) = showsPrec p t
+type instance SourceOf (TermVT src ss ts) = src
+instance Source src => Sourced (TermVT src ss ts) where
+       sourceOf  (TermVT t)     = sourceOf t
+       setSource (TermVT t) src = TermVT $ setSource t src
 
--- * Type family 'Sym_of_Ifaces'
-type family Sym_of_Ifaces (is::[*]) (term:: * -> *) :: Constraint where
-       Sym_of_Ifaces '[] term = ()
-       Sym_of_Ifaces (i ': is) term = (Sym_of_Iface i term, Sym_of_Ifaces is term)
+liftTermVT :: TermVT src ss '[] -> TermVT src ss ts
+liftTermVT (TermVT (Term q t (TeSym te))) =
+       TermVT $ Term @_ @_ @_ @_ @(_ #> _) q t $
+       TeSym $ \_c -> te CtxTeZ
 
--- ** Type family 'Sym_of_Iface'
-type family Sym_of_Iface (i:: *) :: {-term-}(* -> *) -> Constraint
+-- ** Type 'TermAVT'
+-- | Like 'TermVT', but 'CtxTe'-free.
+data TermAVT src ss = forall vs t. TermAVT (forall ts. Term src ss ts vs t)
+type instance SourceOf (TermAVT src ss) = src
+instance Source src => Sourced (TermAVT src ss) where
+       sourceOf  (TermAVT t)     = sourceOf t
+       setSource (TermAVT t) src = TermAVT (setSource t src)
+instance Source src => Eq (TermAVT src ss) where
+       TermAVT x == TermAVT y =
+               let (Term qx' tx' _, Term qy' ty' _) = appendVars x y in
+               isJust $ (qx' #> tx') `eqTypeKi` (qy' #> ty')
+instance Source src => Show (TermAVT src ss) where
+       showsPrec p (TermAVT t) = showsPrec p t
 
--- * Type 'TyConsts_of_Ifaces'
-type TyConsts_of_Ifaces is = Nub (TyConsts_of_IfaceR is)
+-- * Type 'TeSym'
+-- | Symantic of a 'Term'.
+newtype TeSym ss ts (t::K.Type)
+ = TeSym
+ ( forall term.
+   Syms ss term =>
+   Sym_Lambda term =>
+   QualOf t =>
+   CtxTe term ts -> term (UnQualOf t)
+ )
 
--- ** Type family 'TyConsts_of_IfaceR'
-type family TyConsts_of_IfaceR (is::[*]) where
-       TyConsts_of_IfaceR '[] = '[]
-       TyConsts_of_IfaceR (i ': is) = TyConsts_of_Iface i ++ TyConsts_of_IfaceR is
+-- | Like 'TeSym', but 'CtxTe'-free
+-- and using 'inj_Sym' to be able to use 'Sym'@ (@'Proxy'@ s)@ inside.
+teSym ::
+ forall s ss ts t.
+ Inj_Sym ss s =>
+ (forall term. Sym (Proxy s) term => Sym_Lambda term => QualOf t => term (UnQualOf t)) ->
+ TeSym ss ts t
+teSym t = inj_Sym @s (TeSym $ const t)
 
--- ** Type family 'TyConsts_of_Iface'
-type family   TyConsts_of_Iface (i:: *) :: [*]
-type instance TyConsts_of_Iface (Proxy Enum) = Proxy Enum ': TyConsts_imported_by Enum
+-- ** Type family 'QualOf'
+-- | Qualification
+type family QualOf (t::K.Type) :: Constraint where
+       QualOf (q #> t) = q -- (q # QualOf t)
+       QualOf t = (()::Constraint)
 
--- * Type 'LamCtx_Type'
--- | GADT for a typing context,
--- accumulating an @item@ at each lambda;
--- used to accumulate object-types (in 'Expr_From')
--- or host-terms (in 'HostI')
--- associated with the 'LamVar's in scope.
-data LamCtx_Type (is::[*]) (name:: *) (ctx::[*]) where
-       LamCtx_TypeZ :: LamCtx_Type is name '[]
-       LamCtx_TypeS :: name
-                    -> Type (TyConsts_of_Ifaces is) (h::Kind.Type)
-                    -> LamCtx_Type is name hs
-                    -> LamCtx_Type is name (h ': hs)
-infixr 5 `LamCtx_TypeS`
+-- ** Type family 'UnQualOf'
+-- | Unqualification
+type family UnQualOf (t::K.Type) :: K.Type where
+       UnQualOf (q #> t) = t -- UnQualOf t
+       UnQualOf t = t
 
--- * Type 'LamCtx_Term'
-data LamCtx_Term (term:: * -> *) (ctx::[*]) where
-       LamCtx_TermZ :: LamCtx_Term term '[]
-       LamCtx_TermS :: term h
-                    -> LamCtx_Term term hs
-                    -> LamCtx_Term term (h ': hs)
-infixr 5 `LamCtx_TermS`
+-- | Return 'K.Constraint' and 'K.Type' part of given 'Type'.
+unQualTy ::
+ Source src =>
+ Type src vs (t::K.Type) ->
+ ( TypeK src vs K.Constraint
+ , TypeK src vs K.Type )
+unQualTy (TyApp _ (TyApp _ c q) t)
+ | Just HRefl <- proj_ConstKiTy @(K (#>)) @(#>) c
+ = (TypeK q, TypeK t)
+unQualTy t = (TypeK $ noConstraintLen (lenVars t), TypeK t)
 
--- * Type 'Error_Term'
-data Error_Term meta (is::[*])
- =   Error_Term_unbound Term_Name
- |   Error_Term_Typing (Error_Type meta '[Proxy Token_Type])
- |   Error_Term_Con_Type
-     (Either
-       (Con_Type meta '[Proxy Token_Type] (TyConsts_of_Ifaces is))
-       (Con_Type meta is (TyConsts_of_Ifaces is)))
- |   Error_Term_Con_Kind (Con_Kind meta is)
-deriving instance (Eq meta, Eq_Token meta is) => Eq (Error_Term meta is)
-deriving instance (Show meta, Show_Token meta is, Show_TyConst (TyConsts_of_Ifaces is)) => Show (Error_Term meta is)
+-- | Remove 'K.Constraint's from given 'Type'.
+unQualsTy :: Source src => Type src vs (t::kt) -> TypeK src vs kt
+unQualsTy (TyApp _ (TyApp _ c _q) t)
+ | Just HRefl <- proj_ConstKiTy @(K (#>)) @(#>) c
+ = unQualsTy t
+unQualsTy (TyApp src f a)
+ | TypeK f' <- unQualsTy f
+ , TypeK a' <- unQualsTy a
+ = TypeK $ TyApp src f' a'
+unQualsTy t = TypeK t
 
--- * Type 'Con_Type'
-data Con_Type meta ts cs
- =   Con_TyEq  (Either (At meta '[Proxy Token_Type] (EType cs))
-                              (At meta ts (EType cs)))
-                      (At meta ts (EType cs))
- |   Con_TyApp (At meta ts (EType cs))
- |   Con_TyCon (At meta ts (KType cs Constraint))
- |   Con_TyFam (At meta ts TyFamName) [EType cs]
-deriving instance
- ( Eq meta
- , Eq_Token meta ts
- ) => Eq (Con_Type meta ts cs)
-deriving instance
- ( Show meta
- , Show_Token meta ts
- , Show_TyConst cs
- ) => Show (Con_Type meta ts cs)
+-- * Type 'CtxTe'
+-- | GADT for an /interpreting context/:
+-- accumulating at each /lambda abstraction/
+-- the @term@ of the introduced variable.
+data CtxTe (term::K.Type -> K.Type) (hs::[K.Type]) where
+       CtxTeZ :: CtxTe term '[]
+       CtxTeS :: term t
+              -> CtxTe term ts
+              -> CtxTe term (t ': ts)
+infixr 5 `CtxTeS`
 
-instance MonoLift (Error_Type meta '[Proxy Token_Type]) (Error_Term meta ts) where
-       olift = Error_Term_Typing . olift
-instance MonoLift (Error_Term meta ts) (Error_Term meta ts) where
-       olift = Prelude.id
-instance
- cs ~ TyConsts_of_Ifaces is =>
- MonoLift (Con_Type meta is cs) (Error_Term meta is) where
-       olift = Error_Term_Con_Type . Right
-instance
- cs ~ TyConsts_of_Ifaces is =>
- MonoLift (Con_Type meta '[Proxy Token_Type] cs) (Error_Term meta is) where
-       olift = Error_Term_Con_Type . Left
-instance MonoLift (Con_Kind meta '[Proxy Token_Type]) (Error_Term meta is) where
-       olift = Error_Term_Typing . Error_Type_Con_Kind
-instance MonoLift (Con_Kind meta is) (Error_Term meta is) where
-       olift = Error_Term_Con_Kind
+-- ** Type 'TermDef'
+-- | Convenient type alias for defining 'Term'.
+type TermDef s vs t = forall src ss ts. Source src => Inj_Sym ss s => Term src ss ts vs t
 
--- ** Checks
-check_TyEq
- :: MonoLift (Con_Type meta ts cs) err
- => At meta ts (Type cs x)
- -> At meta ts (Type cs y)
- -> ((x :~: y) -> Either err ret) -> Either err ret
-check_TyEq x y k =
-       case unAt x `eq_Type` unAt y of
-        Just Refl -> k Refl
-        Nothing -> Left $ olift $
-               Con_TyEq (Right $ EType <$> x) (EType <$> y)
+-- ** Type family 'Sym'
+type family Sym (s::K.Type) :: {-term-}(K.Type -> K.Type) -> Constraint
 
-check_Type_is
- :: MonoLift (Con_Type meta ts cs) err
- => At meta '[Proxy Token_Type] (Type cs x)
- -> At meta ts (Type cs y)
- -> ((x :~: y) -> Either err ret) -> Either err ret
-check_Type_is x y k =
-       case unAt x `eq_Type` unAt y of
-        Just Refl -> k Refl
-        Nothing -> Left $ olift $
-               Con_TyEq (Left $ EType <$> x) (EType <$> y)
+-- ** Type family 'Syms'
+type family Syms (ss::[K.Type]) (term:: K.Type -> K.Type) :: Constraint where
+       Syms '[] term = ()
+       Syms (s ': ss) term = (Sym s term, Syms ss term)
 
-check_TyApp
- :: MonoLift (Con_Type meta ts cs) err
- => At meta ts (Type cs (fa::kfa))
- -> (forall ka f a. (fa :~: f a)
-  -> Type cs (f::ka -> kfa)
-  -> Type cs (a::ka)
-  -> Either err ret)
- -> Either err ret
-check_TyApp typ k =
-       case unAt typ of
-        a :$ b -> k Refl a b
-        _ -> Left $ olift $
-               Con_TyApp (EType <$> typ)
+-- ** Type 'Inj_Sym'
+-- | Convenient type synonym wrapping 'Inj_SymP'
+-- applied on the correct 'Index'.
+type Inj_Sym ss s = Inj_SymP (Index ss (Proxy s)) ss s
 
-check_TyEq1
- :: ( MonoLift (Con_Type meta ts cs) err
-    , MonoLift (Con_Kind meta ts) err )
- => Type cs (f:: * -> *)
- -> At meta ts (Type cs fa)
- -> (forall a. (fa :~: f a)
-  -> Type cs a
-  -> Either err ret)
- -> Either err ret
-check_TyEq1 typ ty_fa k =
-       check_TyApp ty_fa $ \Refl ty_f ty_a ->
-       check_Kind
-        (At Nothing $ SKiType `SKiArrow` SKiType)
-        (kind_of ty_f <$ ty_fa) $ \Refl ->
-       check_TyEq
-        (At Nothing typ)
-        (ty_f <$ ty_fa) $ \Refl ->
-       k Refl ty_a
+-- | Inject a given /symantic/ @s@ into a list of them,
+-- by returning a function which given a 'TeSym' on @s@
+-- returns the same 'TeSym' on @ss@.
+inj_Sym ::
+ forall s ss ts t.
+ Inj_Sym ss s =>
+ TeSym '[Proxy s] ts t ->
+ TeSym ss ts t
+inj_Sym = inj_SymP (Proxy @(Index ss (Proxy s)))
 
-check_TyEq2
- :: ( MonoLift (Con_Type meta ts cs) err
-    , MonoLift (Con_Kind meta ts) err )
- => Type cs (f:: * -> * -> *)
- -> At meta ts (Type cs fab)
- -> (forall a b. (fab :~: f a b)
-  -> Type cs a
-  -> Type cs b
-  -> Either err ret)
- -> Either err ret
-check_TyEq2 typ ty_fab k =
-       check_TyApp ty_fab            $ \Refl ty_fa ty_b ->
-       check_TyApp (ty_fa <$ ty_fab) $ \Refl ty_f  ty_a ->
-       check_Kind
-        (At Nothing $ SKiType `SKiArrow` SKiType `SKiArrow` SKiType)
-        (kind_of ty_f <$ ty_fab) $ \Refl ->
-       check_TyEq
-        (At Nothing typ)
-        (ty_f <$ ty_fab) $ \Refl ->
-       k Refl ty_a ty_b
+-- *** Class 'Inj_SymP'
+class Inj_SymP p ss s where
+       inj_SymP :: Proxy p -> TeSym '[Proxy s] ts t -> TeSym ss ts t
+instance Inj_SymP Zero (Proxy s ': ss) (s::k) where
+       inj_SymP _ = \(TeSym te) -> TeSym te
+instance Inj_SymP p ss s => Inj_SymP (Succ p) (not_s ': ss) s where
+       inj_SymP _p = \(te::TeSym '[Proxy s] ts t) ->
+               case inj_SymP (Proxy @p) te :: TeSym ss ts t of
+                TeSym te' -> TeSym te'
 
-check_TyCon
- :: ( Proj_TyCon cs
-    , MonoLift (Con_Type meta ts cs) err )
- => At meta ts (Type cs (q::Constraint))
- -> (TyCon q -> Either err ret)
- -> Either err ret
-check_TyCon typ k =
-       case proj_TyCon $ unAt typ of
-        Just TyCon -> k TyCon
-        Nothing -> Left $ olift $
-               Con_TyCon (KType <$> typ)
+-- * Class 'Sym_Lambda'
+class Sym_Lambda term where
+       -- | /Function application/.
+       apply :: term ((a -> b) -> a -> b)
+       default apply :: Sym_Lambda (UnT term) => Trans term => term ((a -> b) -> a -> b)
+       apply = trans apply
+       
+       -- | /Lambda application/.
+       app :: term (a -> b) -> (term a -> term b); infixr 0 `app`
+       default app :: Sym_Lambda (UnT term) => Trans term => term (arg -> res) -> term arg -> term res
+       app = trans2 app
+       
+       -- | /Lambda abstraction/.
+       lam :: (term a -> term b) -> term (a -> b)
+       default lam :: Sym_Lambda (UnT term) => Trans term => (term arg -> term res) -> term (arg -> res)
+       lam f = trans $ lam (unTrans . f . trans)
+       
+       -- | Convenient 'lam' and 'app' wrapper.
+       let_ :: term var -> (term var -> term res) -> term res
+       let_ x f = lam f `app` x
+       
+       -- | /Lambda abstraction/ beta-reducable without duplication
+       -- (i.e. whose variable is used once at most),
+       -- mainly useful in compiled 'Term's
+       -- whose symantics are not a single 'term'
+       -- but a function between 'term's,
+       -- which happens because those are more usable when used as an embedded DSL.
+       lam1 :: (term a -> term b) -> term (a -> b)
+       default lam1 :: Sym_Lambda (UnT term) => Trans term => (term a -> term b) -> term (a -> b)
+       lam1 = lam
+       
+       -- | /Qualification/.
+       --
+       -- Workaround used in 'readTermWithCtx'.
+       qual :: proxy q -> term t -> term (q #> t)
+       default qual :: Sym_Lambda (UnT term) => Trans term => proxy q -> term t -> term (q #> t)
+       qual q = trans1 (qual q)
 
-check_TyCon1
- :: ( Proj_TyCon cs
-    , MonoLift (Con_Type meta ts cs) err
-    , MonoLift (Con_Kind meta ts) err )
- => Type cs con
- -> At meta ts (Type cs (fa:: *))
- -> (forall f a. (fa :~: f a)
-  -> TyCon (con f)
-  -> Type cs (f:: * -> *)
-  -> Type cs (a:: *)
-  -> Either err ret)
- -> Either err ret
-check_TyCon1 con ty_fa k =
-       check_TyApp ty_fa $ \Refl ty_f ty_a ->
-       check_Kind
-        (At Nothing (SKiType `SKiArrow` SKiType))
-        (kind_of ty_f <$ ty_fa) $ \Refl ->
-       check_TyCon ((con :$ ty_f) <$ ty_fa) $ \TyCon ->
-       k Refl TyCon ty_f ty_a
+lam2 :: Sym_Lambda term => (term a -> term b -> term c) -> term (a -> b -> c)
+lam3 :: Sym_Lambda term => (term a -> term b -> term c -> term d) -> term (a -> b -> c -> d)
+lam4 :: Sym_Lambda term => (term a -> term b -> term c -> term d -> term e) -> term (a -> b -> c -> d -> e)
+lam2 f = lam1 $ lam1 . f
+lam3 f = lam1 $ lam2 . f
+lam4 f = lam1 $ lam3 . f
 
-check_TyFam
- :: ( MonoLift (Con_Type meta ts cs) err
-    , Proj_TyFam cs fam
-    , Show fam )
- => At meta ts fam
- -> Types cs hs
- -> (Type cs (TyFam fam hs) -> Either err ret)
- -> Either err ret
-check_TyFam fam tys k =
-       case proj_TyFam (unAt fam) tys of
-        Just t -> k t
-        Nothing -> Left $ olift $
-               Con_TyFam
-                (Text.pack . show <$> fam)
-                (eTypes tys)
+-- Interpreting
+instance Sym_Lambda Eval where
+       apply  = Eval ($)
+       app    = (<*>)
+       lam f  = Eval (unEval . f . Eval)
+       lam1   = lam
+       qual _q (Eval t) = Eval $ Qual t
+       let_ x f = f x -- NOTE: like flip ($)
+instance Sym_Lambda View where
+       apply = View $ \_po _v -> "($)"
+       app (View a1) (View a2) = View $ \po v ->
+               parenInfix po op $
+               a1 (op, SideL) v <> " " <> a2 (op, SideR) v
+               where op = infixN 10
+       lam f = View $ \po v ->
+               let x = "x" <> Text.pack (show v) in
+               parenInfix po op $
+               "\\" <> x <> " -> " <>
+               unView (f (View $ \_po _v -> x)) (op, SideL) (succ v)
+               where op = infixN 1
+       lam1 = lam
+       qual _q (View t) = View t -- TODO: maybe print q
+       let_ x f =
+               View $ \po v ->
+                       let x' = "x" <> Text.pack (show v) in
+                       parenInfix po op $
+                       "let" <> " " <> x' <> " = "
+                        <> unView x (infixN 0, SideL) (succ v) <> " in "
+                        <> unView (f (View $ \_po _v -> x')) (op, SideL) (succ v)
+               where op = infixN 1
+instance (Sym_Lambda r1, Sym_Lambda r2) => Sym_Lambda (Dup r1 r2) where
+       apply = dup0 @Sym_Lambda apply
+       app   = dup2 @Sym_Lambda app
+       lam f = dup_1 lam_f `Dup` dup_2 lam_f
+               where lam_f = lam f
+       lam1 = lam
+       qual q = dup1 @Sym_Lambda (qual q)