Add monomorphic type annotations.

master
James T. Martin 2021-03-26 14:55:23 -07:00
parent 960297e3b5
commit 280096ccb6
Signed by: james
GPG Key ID: 4B7F3DA9351E577C
11 changed files with 301 additions and 182 deletions

View File

@ -114,8 +114,8 @@ commandParser = do
class MonadState AppState m => MonadApp m where class MonadState AppState m => MonadApp m where
parsed :: Either ParseError a -> m a parsed :: Either ParseError a -> m a
typecheckDecl :: Text -> CheckExpr -> m (Maybe Scheme) typecheckDecl :: Maybe Type -> Text -> CheckExpr -> m (Maybe Scheme)
typecheckExpr :: CheckExpr -> m (Maybe Scheme) typecheckExpr :: CheckExpr -> m (Maybe Scheme)
execute :: CheckExpr -> m EvalExpr execute :: CheckExpr -> m EvalExpr
type AppM = ExceptT Text (StateT AppState (InputT IO)) type AppM = ExceptT Text (StateT AppState (InputT IO))
@ -127,8 +127,8 @@ instance MonadApp AppM where
parsed (Left err) = throwError $ T.pack $ show err parsed (Left err) = throwError $ T.pack $ show err
parsed (Right ok) = pure ok parsed (Right ok) = pure ok
typecheckDecl = typecheck . Just typecheckDecl ty = typecheck ty . Just
typecheckExpr = typecheck Nothing typecheckExpr = typecheck Nothing Nothing
execute checkExpr = do execute checkExpr = do
defs <- gets definitions defs <- gets definitions
@ -148,10 +148,10 @@ instance MonadApp AppM where
liftInput $ mapM_ (outputTextLn . unparseEval) trace liftInput $ mapM_ (outputTextLn . unparseEval) trace
pure value pure value
typecheck :: Maybe Text -> CheckExpr -> AppM (Maybe Scheme) typecheck :: Maybe Type -> Maybe Text -> CheckExpr -> AppM (Maybe Scheme)
typecheck decl expr = do typecheck tann decl expr = do
defs <- gets definitions defs <- gets definitions
let type_ = infer $ substitute defs expr let type_ = maybe infer check tann $ substitute defs expr
checkOpts <- gets checkOptions checkOpts <- gets checkOptions
if shouldTypecheck checkOpts if shouldTypecheck checkOpts
then case type_ of then case type_ of
@ -184,10 +184,10 @@ define name expr = modify \appState ->
in appState { definitions = HM.insert name expr' $ definitions appState } in appState { definitions = HM.insert name expr' $ definitions appState }
runDeclOrExpr :: MonadApp m => DeclOrExprAST -> m () runDeclOrExpr :: MonadApp m => DeclOrExprAST -> m ()
runDeclOrExpr (Left (name, exprAST)) = do runDeclOrExpr (Left (name, ty, exprAST)) = do
defs <- gets definitions defs <- gets definitions
let expr = substitute defs $ ast2check exprAST let expr = substitute defs $ ast2check exprAST
_ <- typecheckDecl name expr _ <- typecheckDecl ty name expr
define name expr define name expr
runDeclOrExpr (Right exprAST) = do runDeclOrExpr (Right exprAST) = do
defs <- gets definitions defs <- gets definitions

View File

@ -14,6 +14,7 @@ extra-source-files:
default-extensions: default-extensions:
- BlockArguments - BlockArguments
- ConstraintKinds
- DefaultSignatures - DefaultSignatures
- EmptyCase - EmptyCase
- EmptyDataDeriving - EmptyDataDeriving

View File

@ -14,7 +14,7 @@ import Control.Monad.Loops (iterateM_)
import Control.Monad.State (MonadState, evalState, modify', state, put, gets) import Control.Monad.State (MonadState, evalState, modify', state, put, gets)
import Control.Monad.Writer (runWriterT, tell) import Control.Monad.Writer (runWriterT, tell)
import Data.HashMap.Strict qualified as HM import Data.HashMap.Strict qualified as HM
import Data.Void (Void, absurd) import Data.Void (absurd)
isReducible :: EvalExpr -> Bool isReducible :: EvalExpr -> Bool
-- Applications of function type constructors -- Applications of function type constructors

View File

@ -1,5 +1,5 @@
module Ivo.Evaluator.Base module Ivo.Evaluator.Base
( Identity (..) ( Identity (..), Void
, Expr (..), Ctr (..), Pat, ExprF (..), PatF (..), VoidF, UnitF (..), Text , Expr (..), Ctr (..), Pat, ExprF (..), PatF (..), VoidF, UnitF (..), Text
, substitute, substitute1, rename, rename1, free, bound, used , substitute, substitute1, rename, rename1, free, bound, used
, Eval, EvalExpr, EvalExprF, EvalX, EvalXF (..) , Eval, EvalExpr, EvalExprF, EvalX, EvalXF (..)
@ -17,6 +17,7 @@ import Data.Functor.Identity (Identity (..))
import Data.Functor.Foldable (embed, cata, para) import Data.Functor.Foldable (embed, cata, para)
import Data.HashMap.Strict qualified as HM import Data.HashMap.Strict qualified as HM
import Data.Traversable (for) import Data.Traversable (for)
import Data.Void (Void)
data Eval data Eval
type EvalExpr = Expr Eval type EvalExpr = Expr Eval
@ -24,6 +25,7 @@ type instance AppArgs Eval = EvalExpr
type instance AbsArgs Eval = Text type instance AbsArgs Eval = Text
type instance LetArgs Eval = VoidF EvalExpr type instance LetArgs Eval = VoidF EvalExpr
type instance CtrArgs Eval = UnitF EvalExpr type instance CtrArgs Eval = UnitF EvalExpr
type instance AnnX Eval = Void
type instance XExpr Eval = EvalX type instance XExpr Eval = EvalX
type EvalX = EvalXF EvalExpr type EvalX = EvalXF EvalExpr

View File

@ -1,5 +1,6 @@
module Ivo.Expression module Ivo.Expression
( Expr (..), Ctr (..), Pat, ExprF (..), PatF (..), DefF (..), VoidF, UnitF (..), Text ( Expr (..), Ctr (..), Pat, ExprF (..), PatF (..), DefF (..), VoidF, UnitF (..), Text
, Type (..), TypeF (..), Scheme (..), tapp
, substitute, substitute1, rename, free, bound, used , substitute, substitute1, rename, free, bound, used
, Eval, EvalExpr, EvalX, EvalXF (..), Identity (..) , Eval, EvalExpr, EvalX, EvalXF (..), Identity (..)
, pattern AppFE, pattern CtrE, pattern CtrFE, , pattern AppFE, pattern CtrE, pattern CtrFE,
@ -10,7 +11,6 @@ module Ivo.Expression
, Check, CheckExpr, CheckExprF, CheckX, CheckXF (..) , Check, CheckExpr, CheckExprF, CheckX, CheckXF (..)
, pattern AppFC, pattern CtrC, pattern CtrFC, pattern CallCCC, pattern CallCCFC , pattern AppFC, pattern CtrC, pattern CtrFC, pattern CallCCC, pattern CallCCFC
, pattern FixC, pattern FixFC, pattern HoleC, pattern HoleFC , pattern FixC, pattern FixFC, pattern HoleC, pattern HoleFC
, Type (..), TypeF (..), Scheme (..), tapp
, ast2check, ast2eval, check2eval, check2ast, eval2ast , ast2check, ast2eval, check2eval, check2ast, eval2ast
, builtins , builtins
) where ) where
@ -41,6 +41,7 @@ ast2check = substitute builtins . cata \case
LetRecFP (nx, ex) e -> App (Abs nx e) (App FixC (Abs nx ex)) LetRecFP (nx, ex) e -> App (Abs nx e) (App FixC (Abs nx ex))
CtrF ctr es -> foldl' App (CtrC ctr) es CtrF ctr es -> foldl' App (CtrC ctr) es
CaseF ps -> Case ps CaseF ps -> Case ps
AnnF () e t -> Ann () e t
PNatF n -> int2ast n PNatF n -> int2ast n
PListF es -> mkList es PListF es -> mkList es
PStrF s -> mkList $ map (App (CtrC CChar) . int2ast . fromEnum) $ unpack s PStrF s -> mkList $ map (App (CtrC CChar) . int2ast . fromEnum) $ unpack s
@ -63,6 +64,7 @@ check2eval = cata \case
LetF (Def nx ex) e -> App (Abs nx e) ex LetF (Def nx ex) e -> App (Abs nx e) ex
CtrFC ctr -> CtrE ctr CtrFC ctr -> CtrE ctr
CaseF ps -> Case ps CaseF ps -> Case ps
AnnF () e _ -> e
CallCCFC -> CallCCE CallCCFC -> CallCCE
FixFC -> z FixFC -> z
HoleFC -> omega HoleFC -> omega
@ -88,6 +90,7 @@ check2ast = hoist go . rename (HM.keysSet builtins)
LetF (Def nx ex) e -> LetFP ((nx, ex) :| []) e LetF (Def nx ex) e -> LetFP ((nx, ex) :| []) e
CtrFC ctr -> CtrF ctr [] CtrFC ctr -> CtrF ctr []
CaseF ps -> CaseF ps CaseF ps -> CaseF ps
AnnF () e t -> AnnF () e t
CallCCFC-> VarF "callcc" CallCCFC-> VarF "callcc"
FixFC -> VarF "fix" FixFC -> VarF "fix"
HoleFC -> HoleFP HoleFC -> HoleFP

View File

@ -1,9 +1,11 @@
{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TemplateHaskell #-}
{-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UndecidableSuperClasses #-}
module Ivo.Expression.Base module Ivo.Expression.Base
( Text, VoidF, UnitF (..), absurd' ( Text, VoidF, UnitF (..), absurd'
, Expr (..), Ctr (..), Pat, Def, AppArgs, AbsArgs, LetArgs, CtrArgs, XExpr , Expr (..), Ctr (..), Pat, Def, AppArgs, AbsArgs, LetArgs, CtrArgs, AnnX, XExpr
, ExprF (..), PatF (..), DefF (..), AppArgsF, LetArgsF, CtrArgsF, XExprF , ExprF (..), PatF (..), DefF (..), AppArgsF, LetArgsF, CtrArgsF, XExprF
, Type (..), TypeF (..), Scheme (..), tapp
, RecursivePhase, projectAppArgs, projectLetArgs, projectCtrArgs, projectXExpr, projectDef , RecursivePhase, projectAppArgs, projectLetArgs, projectCtrArgs, projectXExpr, projectDef
, embedAppArgs, embedLetArgs, embedCtrArgs, embedXExpr, embedDef , embedAppArgs, embedLetArgs, embedCtrArgs, embedXExpr, embedDef
, Substitutable, free, bound, used, collectVars, rename, rename1 , Substitutable, free, bound, used, collectVars, rename, rename1
@ -15,30 +17,34 @@ import Control.Monad.Reader (MonadReader, Reader, runReader, asks, local)
import Control.Monad.State (MonadState, StateT, evalStateT, state) import Control.Monad.State (MonadState, StateT, evalStateT, state)
import Control.Monad.Zip (MonadZip, mzipWith) import Control.Monad.Zip (MonadZip, mzipWith)
import Data.Foldable (fold) import Data.Foldable (fold)
import Data.Functor.Foldable (Base, Recursive, Corecursive, project, embed) import Data.Functor.Foldable (Base, Recursive, Corecursive, project, embed, cata)
import Data.Functor.Foldable.TH (makeBaseFunctor)
import Data.HashMap.Strict (HashMap) import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HM import Data.HashMap.Strict qualified as HM
import Data.HashSet (HashSet) import Data.HashSet (HashSet)
import Data.HashSet qualified as HS import Data.HashSet qualified as HS
import Data.Kind (Type) import Data.Kind qualified as Kind
import Data.List (foldl1')
import Data.Stream qualified as S import Data.Stream qualified as S
import Data.Text (Text) import Data.Text (Text)
import Data.Text qualified as T import Data.Text qualified as T
data Expr phase data Expr phase
-- | A variable: `x`. -- | A variable: @x@.
= Var !Text = Var !Text
-- | Function application: `f x_0 ... x_n`. -- | Function application: @f x_0 ... x_n@.
| App !(Expr phase) !(AppArgs phase) | App !(Expr phase) !(AppArgs phase)
-- | Lambda abstraction: `λx_0 ... x_n. e`. -- | Lambda abstraction: @λx_0 ... x_n. e@.
| Abs !(AbsArgs phase) !(Expr phase) | Abs !(AbsArgs phase) !(Expr phase)
-- | Let expression: `let x_0 = v_0 ... ; x_n = v_n in e`. -- | Let expression: @let x_0 = v_0 ... ; x_n = v_n in e@.
| Let !(LetArgs phase) !(Expr phase) | Let !(LetArgs phase) !(Expr phase)
-- | Data constructor, e.g. `(x, y)` or `Left`. -- | Data constructor, e.g. @(x, y)@ or @Left@.
| Ctr !Ctr !(CtrArgs phase) | Ctr !Ctr !(CtrArgs phase)
-- | Case expression to pattern match against a value, -- | Case expression to pattern match against a value,
-- e.g. `case { Left x1 -> e1 ; Right x2 -> e2 }`. -- e.g. @case { Left x1 -> e1 ; Right x2 -> e2 }@.
| Case ![Pat phase] | Case ![Pat phase]
-- | Type annotations: @expr : type@.
| Ann !(AnnX phase) !(Expr phase) Type
-- | Additional phase-specific constructors. -- | Additional phase-specific constructors.
| ExprX !(XExpr phase) | ExprX !(XExpr phase)
@ -46,23 +52,30 @@ type family AppArgs phase
type family AbsArgs phase type family AbsArgs phase
type family LetArgs phase type family LetArgs phase
type family CtrArgs phase type family CtrArgs phase
type family AnnX phase
type family XExpr phase type family XExpr phase
deriving instance class
( Eq (AppArgs phase) ( c (AppArgs phase)
, Eq (AbsArgs phase) , c (AbsArgs phase)
, Eq (LetArgs phase) , c (LetArgs phase)
, Eq (CtrArgs phase) , c (CtrArgs phase)
, Eq (XExpr phase) , c (AnnX phase)
) => Eq (Expr phase) , c (XExpr phase)
) => ForallX c phase
deriving instance instance
( Show (AppArgs phase) ( c (AppArgs phase)
, Show (AbsArgs phase) , c (AbsArgs phase)
, Show (LetArgs phase) , c (LetArgs phase)
, Show (CtrArgs phase) , c (CtrArgs phase)
, Show (XExpr phase) , c (AnnX phase)
) => Show (Expr phase) , c (XExpr phase)
) => ForallX c phase
deriving instance ForallX Eq phase => Eq (Expr phase)
deriving instance ForallX Show phase => Show (Expr phase)
-- | Data constructors (used in pattern matching and literals). -- | Data constructors (used in pattern matching and literals).
data Ctr data Ctr
@ -94,6 +107,41 @@ data PatF r = Pat { patCtr :: !Ctr, patNames :: ![Text], patBody :: !r }
-- | A definition, mapping a name to a value. -- | A definition, mapping a name to a value.
type Def phase = (Text, Expr phase) type Def phase = (Text, Expr phase)
-- | A monomorphic type.
data Type
-- | Type variable.
= TVar Text
-- | Type application.
| TApp Type Type
-- | The function type.
| TAbs
-- | The product type.
| TProd
-- | The sum type.
| TSum
-- | The unit type.
| TUnit
-- | The empty type.
| TVoid
-- | The type of natural numbers.
| TNat
-- | The type of lists.
| TList
-- | The type of characters.
| TChar
deriving (Eq, Show)
tapp :: [Type] -> Type
tapp [] = error "Empty type applications are not permitted"
tapp [t] = t
tapp ts = foldl1' TApp ts
-- | A polymorphic type.
data Scheme
-- | Universally quantified type variables.
= TForall [Text] Type
deriving (Eq, Show)
--- ---
--- Base functor boilerplate for recursion-schemes --- Base functor boilerplate for recursion-schemes
--- ---
@ -105,14 +153,29 @@ data ExprF phase r
| LetF !(LetArgsF phase r) r | LetF !(LetArgsF phase r) r
| CtrF Ctr (CtrArgsF phase r) | CtrF Ctr (CtrArgsF phase r)
| CaseF [PatF r] | CaseF [PatF r]
| AnnF !(AnnX phase) r Type
| ExprXF !(XExprF phase r) | ExprXF !(XExprF phase r)
type instance Base (Expr phase) = ExprF phase type instance Base (Expr phase) = ExprF phase
type family AppArgsF phase :: Type -> Type type family AppArgsF phase :: Kind.Type -> Kind.Type
type family LetArgsF phase :: Type -> Type type family LetArgsF phase :: Kind.Type -> Kind.Type
type family CtrArgsF phase :: Type -> Type type family CtrArgsF phase :: Kind.Type -> Kind.Type
type family XExprF phase :: Type -> Type type family XExprF phase :: Kind.Type -> Kind.Type
class
( c (AppArgsF phase)
, c (LetArgsF phase)
, c (CtrArgsF phase)
, c (XExprF phase)
) => ForallXF c phase
instance
( c (AppArgsF phase)
, c (LetArgsF phase)
, c (CtrArgsF phase)
, c (XExprF phase)
) => ForallXF c phase
data DefF r = Def !Text !r data DefF r = Def !Text !r
deriving (Eq, Functor, Foldable, Traversable, Show) deriving (Eq, Functor, Foldable, Traversable, Show)
@ -128,12 +191,7 @@ data VoidF a
absurd' :: VoidF a -> b absurd' :: VoidF a -> b
absurd' x = case x of {} absurd' x = case x of {}
instance instance ForallXF Functor phase => Functor (ExprF phase) where
( Functor (AppArgsF phase)
, Functor (LetArgsF phase)
, Functor (CtrArgsF phase)
, Functor (XExprF phase)
) => Functor (ExprF phase) where
fmap f = \case fmap f = \case
VarF n -> VarF n VarF n -> VarF n
AppF ef exs -> AppF (f ef) (fmap f exs) AppF ef exs -> AppF (f ef) (fmap f exs)
@ -141,14 +199,10 @@ instance
LetF ds e -> LetF (fmap f ds) (f e) LetF ds e -> LetF (fmap f ds) (f e)
CtrF c es -> CtrF c (fmap f es) CtrF c es -> CtrF c (fmap f es)
CaseF ps -> CaseF (fmap (fmap f) ps) CaseF ps -> CaseF (fmap (fmap f) ps)
AnnF x e t -> AnnF x (f e) t
ExprXF q -> ExprXF (fmap f q) ExprXF q -> ExprXF (fmap f q)
instance instance ForallXF Foldable phase => Foldable (ExprF phase) where
( Foldable (AppArgsF phase)
, Foldable (LetArgsF phase)
, Foldable (CtrArgsF phase)
, Foldable (XExprF phase)
) => Foldable (ExprF phase) where
foldMap f = \case foldMap f = \case
VarF _ -> mempty VarF _ -> mempty
AppF ef exs -> f ef <> foldMap f exs AppF ef exs -> f ef <> foldMap f exs
@ -156,14 +210,10 @@ instance
LetF ds e -> foldMap f ds <> f e LetF ds e -> foldMap f ds <> f e
CtrF _ es -> foldMap f es CtrF _ es -> foldMap f es
CaseF ps -> foldMap (foldMap f) ps CaseF ps -> foldMap (foldMap f) ps
AnnF _ e _ -> f e
ExprXF q -> foldMap f q ExprXF q -> foldMap f q
instance instance ForallXF Traversable phase => Traversable (ExprF phase) where
( Traversable (AppArgsF phase)
, Traversable (LetArgsF phase)
, Traversable (CtrArgsF phase)
, Traversable (XExprF phase)
) => Traversable (ExprF phase) where
traverse f = \case traverse f = \case
VarF n -> pure $ VarF n VarF n -> pure $ VarF n
AppF ef exs -> AppF <$> f ef <*> traverse f exs AppF ef exs -> AppF <$> f ef <*> traverse f exs
@ -171,6 +221,7 @@ instance
LetF ds e -> LetF <$> traverse f ds <*> f e LetF ds e -> LetF <$> traverse f ds <*> f e
CtrF c es -> CtrF c <$> traverse f es CtrF c es -> CtrF c <$> traverse f es
CaseF ps -> CaseF <$> traverse (traverse f) ps CaseF ps -> CaseF <$> traverse (traverse f) ps
AnnF x e t -> (\e' -> AnnF x e' t) <$> f e
ExprXF q -> ExprXF <$> traverse f q ExprXF q -> ExprXF <$> traverse f q
class Functor (ExprF phase) => RecursivePhase phase where class Functor (ExprF phase) => RecursivePhase phase where
@ -226,6 +277,7 @@ instance RecursivePhase phase => Recursive (Expr phase) where
Let ds e -> LetF (projectLetArgs ds) e Let ds e -> LetF (projectLetArgs ds) e
Ctr c es -> CtrF c (projectCtrArgs es) Ctr c es -> CtrF c (projectCtrArgs es)
Case ps -> CaseF ps Case ps -> CaseF ps
Ann x e t -> AnnF x e t
ExprX q -> ExprXF (projectXExpr q) ExprX q -> ExprXF (projectXExpr q)
instance RecursivePhase phase => Corecursive (Expr phase) where instance RecursivePhase phase => Corecursive (Expr phase) where
@ -236,8 +288,11 @@ instance RecursivePhase phase => Corecursive (Expr phase) where
LetF ds e -> Let (embedLetArgs ds) e LetF ds e -> Let (embedLetArgs ds) e
CtrF c es -> Ctr c (embedCtrArgs es) CtrF c es -> Ctr c (embedCtrArgs es)
CaseF ps -> Case ps CaseF ps -> Case ps
AnnF x e t -> Ann x e t
ExprXF q -> ExprX (embedXExpr q) ExprXF q -> ExprX (embedXExpr q)
makeBaseFunctor ''Type
--- ---
--- End base functor boilerplate. --- End base functor boilerplate.
--- ---
@ -283,6 +338,34 @@ class Substitutable e where
unsafeSubstitute1 :: Text -> e -> e -> e unsafeSubstitute1 :: Text -> e -> e -> e
unsafeSubstitute1 n e = unsafeSubstitute (HM.singleton n e) unsafeSubstitute1 n e = unsafeSubstitute (HM.singleton n e)
instance Substitutable Type where
collectVars withVar _ = cata \case
TVarF n -> withVar n
t -> fold t
-- /All/ variables in a monomorphic type are free.
rename _ t = t
-- No renaming step is necessary.
substitute substs = cata \case
TVarF n -> HM.findWithDefault (TVar n) n substs
e -> embed e
unsafeSubstitute = substitute
instance Substitutable Scheme where
collectVars withVar withBinder (TForall names t) =
foldMap withBinder names $ collectVars withVar withBinder t
rename = runRenamer \badNames (TForall names t) ->
uncurry TForall <$> replaceNames badNames names (pure t)
-- I took a shot at implementing this but found it to be quite difficult
-- because merging the foralls is tricky.
-- It's not undoable, but it wasn't worth my further time investment
-- seeing as this function isn't currently used anywhere.
unsafeSubstitute = error "Substitution for schemes not yet implemented"
-- --
-- These primitives are likely to be useful for implementing `rename`. -- These primitives are likely to be useful for implementing `rename`.
-- Ideally, I would like to find a way to move the implementation of `rename` here entirely, -- Ideally, I would like to find a way to move the implementation of `rename` here entirely,

View File

@ -1,5 +1,6 @@
module Ivo.Syntax.Base module Ivo.Syntax.Base
( Expr (..), ExprF (..), Ctr (..), Pat, Def, DefF (..), PatF (..), VoidF, Text, NonEmpty (..) ( Expr (..), ExprF (..), Ctr (..), Pat, Def, DefF (..), PatF (..), VoidF, Text, NonEmpty (..)
, Type (..), TypeF (..), Scheme (..), tapp
, substitute, substitute1, rename, rename1, free, bound, used , substitute, substitute1, rename, rename1, free, bound, used
, Parse, AST, ASTF, ASTX, ASTXF (..), NonEmptyDefFs (..) , Parse, AST, ASTF, ASTX, ASTXF (..), NonEmptyDefFs (..)
, pattern LetFP, pattern LetRecP, pattern LetRecFP , pattern LetFP, pattern LetRecP, pattern LetRecFP
@ -36,6 +37,7 @@ type instance AppArgs Parse = NonEmpty AST
type instance AbsArgs Parse = NonEmpty Text type instance AbsArgs Parse = NonEmpty Text
type instance LetArgs Parse = NonEmpty (Def Parse) type instance LetArgs Parse = NonEmpty (Def Parse)
type instance CtrArgs Parse = [AST] type instance CtrArgs Parse = [AST]
type instance AnnX Parse = ()
type instance XExpr Parse = ASTX type instance XExpr Parse = ASTX
type ASTX = ASTXF AST type ASTX = ASTXF AST
@ -107,10 +109,10 @@ pattern HoleP = ExprX HoleP_
pattern HoleFP :: ASTF r pattern HoleFP :: ASTF r
pattern HoleFP = ExprXF HoleP_ pattern HoleFP = ExprXF HoleP_
{-# COMPLETE VarF, AppF, AbsF, LetFP, CtrF, CaseF, ExprXF #-} {-# COMPLETE VarF, AppF, AbsF, LetFP, CtrF, CaseF, AnnF, ExprXF #-}
{-# COMPLETE Var, App, Abs, Let, Ctr, Case, LetRecP, PNat, PList, PChar, PStr, HoleP #-} {-# COMPLETE Var, App, Abs, Let, Ctr, Case, Ann, LetRecP, PNat, PList, PChar, PStr, HoleP #-}
{-# COMPLETE VarF, AppF, AbsF, LetF , CtrF, CaseF, LetRecFP, PNatF, PListF, PCharF, PStrF, HoleFP #-} {-# COMPLETE VarF, AppF, AbsF, LetF , CtrF, CaseF, AnnF, LetRecFP, PNatF, PListF, PCharF, PStrF, HoleFP #-}
{-# COMPLETE VarF, AppF, AbsF, LetFP, CtrF, CaseF, LetRecFP, PNatF, PListF, PCharF, PStrF, HoleFP #-} {-# COMPLETE VarF, AppF, AbsF, LetFP, CtrF, CaseF, AnnF, LetRecFP, PNatF, PListF, PCharF, PStrF, HoleFP #-}
-- TODO: Implement Substitutable for AST. -- TODO: Implement Substitutable for AST.

View File

@ -1,17 +1,19 @@
module Ivo.Syntax.Parser module Ivo.Syntax.Parser
( ParseError, parse ( ParseError, parse
, DeclOrExprAST, ProgramAST , Declaration, DeclOrExprAST, ProgramAST
, parseAST, parseDeclOrExpr, parseProgram , parseAST, parseDeclOrExpr, parseProgram
, astParser, declOrExprParser, programParser , typeParser, schemeParser, astParser, declOrExprParser, programParser
) where ) where
import Ivo.Syntax.Base import Ivo.Syntax.Base
import Data.Functor.Identity (Identity)
import Data.List.NonEmpty (fromList) import Data.List.NonEmpty (fromList)
import Data.Text qualified as T import Data.Text qualified as T
import Prelude hiding (succ, either) import Prelude hiding (succ, either)
import Text.Parsec hiding (label, token, spaces) import Text.Parsec hiding (label, token, spaces)
import Text.Parsec qualified import Text.Parsec qualified
import Text.Parsec.Expr
import Text.Parsec.Text (Parser) import Text.Parsec.Text (Parser)
spaces :: Parser () spaces :: Parser ()
@ -36,7 +38,7 @@ token :: Char -> Parser ()
token ch = label [ch] $ char ch *> spaces token ch = label [ch] $ char ch *> spaces
keywords :: [Text] keywords :: [Text]
keywords = ["let", "in", "Left", "Right", "S", "Z", "Char"] keywords = ["let", "in", "Left", "Right", "S", "Z", "forall", "Char", "Void", "Unit", "Nat", "Char"]
-- | A keyword is an exact string which is not part of an identifier. -- | A keyword is an exact string which is not part of an identifier.
keyword :: Text -> Parser () keyword :: Text -> Parser ()
@ -56,6 +58,9 @@ identifier = label "identifier" $ do
variable :: Parser AST variable :: Parser AST
variable = label "variable" $ Var <$> identifier variable = label "variable" $ Var <$> identifier
tvariable :: Parser Type
tvariable = label "variable" $ TVar <$> identifier
many1' :: Parser a -> Parser (NonEmpty a) many1' :: Parser a -> Parser (NonEmpty a)
many1' p = fromList <$> many1 p many1' p = fromList <$> many1 p
@ -65,22 +70,29 @@ many2 p = (,) <$> p <*> many1' p
grouping :: Parser AST grouping :: Parser AST
grouping = label "grouping" $ between (token '(') (token ')') ambiguous grouping = label "grouping" $ between (token '(') (token ')') ambiguous
tgrouping :: Parser Type
tgrouping = label "grouping" $ between (token '(') (token ')') tambiguous
application :: Parser AST application :: Parser AST
application = uncurry App <$> many2 block application = label "application" $ uncurry App <$> many2 block
tapplication :: Parser Type
tapplication = label "application" $ uncurry tapp' <$> many2 tblock
where tapp' t1 (t2 :| ts) = tapp (t1 : t2 : ts)
abstraction :: Parser AST abstraction :: Parser AST
abstraction = label "lambda abstraction" $ Abs <$> between lambda (token '.') (many1' identifier) <*> ambiguous abstraction = label "lambda abstraction" $ Abs <$> between lambda (token '.') (many1' identifier) <*> ambiguous
where lambda = label "lambda" $ (char '\\' <|> char 'λ') *> spaces where lambda = label "lambda" $ (char '\\' <|> char 'λ') *> spaces
definition :: Parser (Def Parse) definition :: Parser (Def Parse)
definition = do definition = label "definition" $ do
name <- identifier name <- identifier
token '=' token '='
value <- ambiguous value <- ambiguous
pure (name, value) pure (name, value)
let_ :: Parser AST let_ :: Parser AST
let_ = letrecstar <|> letstar let_ = label "let expression" $ letrecstar <|> letstar
where where
letrecstar = LetRecP <$> between (try (keyword "letrec")) (keyword "in") definition <*> ambiguous letrecstar = LetRecP <$> between (try (keyword "letrec")) (keyword "in") definition <*> ambiguous
letstar = Let <$> between (keyword "let") (keyword "in") definitions <*> ambiguous letstar = Let <$> between (keyword "let") (keyword "in") definitions <*> ambiguous
@ -89,7 +101,7 @@ let_ = letrecstar <|> letstar
definitions = fromList <$> sepBy1 definition (token ';') definitions = fromList <$> sepBy1 definition (token ';')
ctr :: Parser AST ctr :: Parser AST
ctr = pair <|> unit <|> either <|> nat <|> list <|> str ctr = label "data constructor" $ pair <|> unit <|> either <|> nat <|> list <|> str
where where
unit, pairCtr, tuple, either, left, right, unit, pairCtr, tuple, either, left, right,
zero, succ, natLit, consCtr, cons, charCtr, charLit, strLit :: Parser AST zero, succ, natLit, consCtr, cons, charCtr, charLit, strLit :: Parser AST
@ -166,9 +178,62 @@ case_ = label "case patterns" $ do
token '}' token '}'
pure $ Case pats pure $ Case pats
ann :: Parser AST
ann = label "type annotation" $ do
e <- block
token ':'
t <- tambiguous
pure (Ann () e t)
hole :: Parser AST hole :: Parser AST
hole = label "hole" $ HoleP <$ token '_' hole = label "hole" $ HoleP <$ token '_'
tlist :: Parser Type
tlist = between (token '[') (token ']') $ ((TApp TList <$> tambiguous) <|> pure TList)
tinfix :: Parser Type
tinfix = buildExpressionParser ttable tblock
where
ttable :: [[Operator Text () Identity Type]]
ttable = [ [Infix (binop TAbs <$ arrSym) AssocRight]
, [Infix (binop TProd <$ token '*') AssocRight]
, [Infix (binop TSum <$ token '+') AssocRight]
]
arrSym :: Parser ()
arrSym = token '→' <|> keyword "->"
binop :: Type -> Type -> Type -> Type
binop c t1 t2 = TApp (TApp c t1) t2
tctr :: Parser Type
tctr = tlist <|> tunit <|> tvoid <|> tnat <|> tchar
where
tunit = TUnit <$ (keyword "Unit" <|> keyword "")
tvoid = TVoid <$ (keyword "Void" <|> keyword "")
tnat = TNat <$ (keyword "Nat" <|> keyword "")
tchar = TChar <$ keyword "Char"
tfinite :: Parser Type
tfinite = tvariable <|> tlist <|> tctr <|> tgrouping
tblock :: Parser Type
tblock = tfinite
tambiguous :: Parser Type
tambiguous = try tinfix <|> try tapplication <|> tblock
tforall :: Parser Scheme
tforall = do
keyword "forall" <|> token '∀'
names <- many1 (identifier <* spaces)
token '.'
ty <- tambiguous
pure $ TForall names ty
scheme :: Parser Scheme
scheme = tforall <|> (TForall [] <$> tambiguous)
-- | Guaranteed to consume a finite amount of input -- | Guaranteed to consume a finite amount of input
finite :: Parser AST finite :: Parser AST
finite = label "finite expression" $ variable <|> hole <|> ctr <|> case_ <|> grouping finite = label "finite expression" $ variable <|> hole <|> ctr <|> case_ <|> grouping
@ -179,7 +244,13 @@ block = label "block expression" $ abstraction <|> let_ <|> finite
-- | Not guaranteed to consume input at all, may continue until it reaches a terminator -- | Not guaranteed to consume input at all, may continue until it reaches a terminator
ambiguous :: Parser AST ambiguous :: Parser AST
ambiguous = label "any expression" $ try application <|> block ambiguous = label "any expression" $ try ann <|> try application <|> block
typeParser :: Parser Type
typeParser = tambiguous
schemeParser :: Parser Scheme
schemeParser = scheme
astParser :: Parser AST astParser :: Parser AST
astParser = ambiguous astParser = ambiguous
@ -187,18 +258,26 @@ astParser = ambiguous
parseAST :: Text -> Either ParseError AST parseAST :: Text -> Either ParseError AST
parseAST = parse (spaces *> ambiguous <* eof) "input" parseAST = parse (spaces *> ambiguous <* eof) "input"
type Declaration = (Text, AST) type Declaration = (Text, Maybe Type, AST)
definitionAnn :: Parser Declaration
definitionAnn = do
name <- identifier
ty <- optionMaybe $ token ':' *> tambiguous
token '='
e <- ambiguous
pure (name, ty, e)
declaration :: Parser Declaration declaration :: Parser Declaration
declaration = notFollowedBy (try let_) >> (declrec <|> decl) declaration = notFollowedBy (try let_) >> (declrec <|> decl)
where where
declrec = do declrec = do
try $ keyword "letrec" try $ keyword "letrec"
(name, expr) <- definition (name, ty, expr) <- definitionAnn
pure (name, LetRecP (name, expr) (Var name)) pure (name, ty, LetRecP (name, expr) (Var name))
decl = do decl = do
keyword "let" keyword "let"
definition definitionAnn
-- | A program is a series of declarations and expressions to execute. -- | A program is a series of declarations and expressions to execute.
type ProgramAST = [DeclOrExprAST] type ProgramAST = [DeclOrExprAST]

View File

@ -1,10 +1,11 @@
module Ivo.Syntax.Printer (unparseAST) where module Ivo.Syntax.Printer (unparseAST, unparseType, unparseScheme) where
import Ivo.Syntax.Base import Ivo.Syntax.Base
import Data.Functor.Base (NonEmptyF (NonEmptyF)) import Data.Functor.Base (NonEmptyF (NonEmptyF))
import Data.Functor.Foldable (cata) import Data.Functor.Foldable (cata)
import Data.List.NonEmpty (toList) import Data.List.NonEmpty (toList)
import Data.Text qualified as T
import Data.Text.Lazy (fromStrict, toStrict, intercalate, unwords, singleton) import Data.Text.Lazy (fromStrict, toStrict, intercalate, unwords, singleton)
import Data.Text.Lazy.Builder (Builder, fromText, fromLazyText, toLazyText, fromString) import Data.Text.Lazy.Builder (Builder, fromText, fromLazyText, toLazyText, fromString)
import Prelude hiding (unwords) import Prelude hiding (unwords)
@ -62,6 +63,7 @@ unparseAST = toStrict . toLazyText . snd . cata \case
CaseF pats -> CaseF pats ->
let pats' = fromLazyText $ intercalate "; " $ map (toLazyText . unparsePat) pats let pats' = fromLazyText $ intercalate "; " $ map (toLazyText . unparsePat) pats
in tag Finite $ "{ " <> pats' <> " }" in tag Finite $ "{ " <> pats' <> " }"
AnnF () e t -> tag Ambiguous $ final e <> " : " <> fromText (unparseType t)
PNatF n -> tag Finite $ fromString $ show n PNatF n -> tag Finite $ fromString $ show n
PListF es -> PListF es ->
let es' = fromLazyText $ intercalate ", " $ map (toLazyText . unambiguous) es let es' = fromLazyText $ intercalate ", " $ map (toLazyText . unambiguous) es
@ -95,3 +97,28 @@ unparseAST = toStrict . toLazyText . snd . cata \case
unparsePat (Pat ctr ns e) unparsePat (Pat ctr ns e)
= unambiguous (unparseCtr ctr (map (tag Finite . fromText) ns)) <> " -> " <> unambiguous e = unambiguous (unparseCtr ctr (map (tag Finite . fromText) ns)) <> " -> " <> unambiguous e
-- HACK
pattern TApp2 :: Type -> Type -> Type -> Type
pattern TApp2 tf tx ty = TApp (TApp tf tx) ty
-- TODO: Improve these printers.
unparseType :: Type -> Text
unparseType (TVar name) = name
unparseType (TApp2 TAbs a b) = "(" <> unparseType a <> " -> " <> unparseType b <> ")"
unparseType (TApp2 TProd a b) = "(" <> unparseType a <> " * " <> unparseType b <> ")"
unparseType (TApp2 TSum a b) = "(" <> unparseType a <> " + " <> unparseType b <> ")"
unparseType (TApp TList a) = "[" <> unparseType a <> "]"
unparseType (TApp a b) = "(" <> unparseType a <> " " <> unparseType b <> ")"
unparseType TAbs = "(->)"
unparseType TProd = "(*)"
unparseType TSum = "(+)"
unparseType TUnit = ""
unparseType TVoid = ""
unparseType TNat = "Nat"
unparseType TList = "[]"
unparseType TChar = "Char"
unparseScheme :: Scheme -> Text
unparseScheme (TForall [] t) = unparseType t
unparseScheme (TForall names t) = "" <> T.unwords names <> ". " <> unparseType t

View File

@ -1,8 +1,9 @@
module Ivo.Types module Ivo.Types
( module Ivo.Types.Base ( module Ivo.Types.Base
, infer , infer, check
) where ) where
import Ivo.Syntax.Printer
import Ivo.Types.Base import Ivo.Types.Base
import Control.Applicative ((<|>)) import Control.Applicative ((<|>))
@ -99,6 +100,10 @@ j (Case ctrs) = do
j (CtrC ctr) = do j (CtrC ctr) = do
(t_ret, ts_n) <- ctrTy ctr (t_ret, ts_n) <- ctrTy ctr
pure $ foldr (\t_a t_r -> tapp [TAbs, t_a, t_r]) t_ret ts_n pure $ foldr (\t_a t_r -> tapp [TAbs, t_a, t_r]) t_ret ts_n
j (Ann () e t_ann) = do
t_ret <- j e
unify t_ret t_ann
pure t_ann
j CallCCC = do j CallCCC = do
t_a <- fresh t_a <- fresh
t_b <- fresh t_b <- fresh
@ -156,3 +161,13 @@ infer e = do
s <- solve' c s <- solve' c
let t' = substitute s t let t' = substitute s t
pure $ runReader (generalize t') HM.empty pure $ runReader (generalize t') HM.empty
check :: Type -> CheckExpr -> Either Text Scheme
check t_ann e = do
(t, c) <- runInferencer do
t_ret <- j e
unify t_ret t_ann
pure t_ann
s <- solve' c
let t' = substitute s t
pure $ runReader (generalize t') HM.empty

View File

@ -1,30 +1,26 @@
{-# LANGUAGE TemplateHaskell #-}
module Ivo.Types.Base module Ivo.Types.Base
( Identity (..) ( Identity (..)
, Expr (..), Ctr (..), Pat, ExprF (..), PatF (..), VoidF, UnitF (..), Text , Expr (..), Ctr (..), Pat, ExprF (..), PatF (..), VoidF, UnitF (..), Text
, Type (..), TypeF (..), Scheme (..), tapp
, substitute, substitute1, rename, rename1, free, bound, used , substitute, substitute1, rename, rename1, free, bound, used
, Check, CheckExpr, CheckExprF, CheckX, CheckXF (..) , Check, CheckExpr, CheckExprF, CheckX, CheckXF (..)
, pattern AppFC, pattern CtrC, pattern CtrFC, pattern CallCCC, pattern CallCCFC , pattern AppFC, pattern CtrC, pattern CtrFC, pattern CallCCC, pattern CallCCFC
, pattern FixC, pattern FixFC, pattern HoleC, pattern HoleFC , pattern FixC, pattern FixFC, pattern HoleC, pattern HoleFC
, Type (..), TypeF (..), Scheme (..), tapp
, Substitution, Context, Constraint , Substitution, Context, Constraint
, MonoSubstitutable, substituteMono, substituteMono1 , MonoSubstitutable, substituteMono, substituteMono1
, unparseType, unparseScheme
) where ) where
import Ivo.Expression.Base
import Control.Monad (forM) import Control.Monad (forM)
import Control.Monad.Reader (asks) import Control.Monad.Reader (asks)
import Data.Bifunctor (bimap, first) import Data.Bifunctor (bimap, first)
import Data.Foldable (fold) import Data.Foldable (fold)
import Data.Functor.Foldable (embed, cata, para) import Data.Functor.Foldable (embed, cata, para)
import Data.Functor.Foldable.TH (makeBaseFunctor)
import Data.Functor.Identity (Identity (..)) import Data.Functor.Identity (Identity (..))
import Data.HashMap.Strict (HashMap) import Data.HashMap.Strict (HashMap)
import Data.HashMap.Strict qualified as HM import Data.HashMap.Strict qualified as HM
import Data.List (foldl1')
import Data.Text qualified as T
import Data.Traversable (for) import Data.Traversable (for)
import Ivo.Expression.Base
data Check data Check
type CheckExpr = Expr Check type CheckExpr = Expr Check
@ -32,6 +28,7 @@ type instance AppArgs Check = CheckExpr
type instance AbsArgs Check = Text type instance AbsArgs Check = Text
type instance LetArgs Check = (Text, CheckExpr) type instance LetArgs Check = (Text, CheckExpr)
type instance CtrArgs Check = UnitF CheckExpr type instance CtrArgs Check = UnitF CheckExpr
type instance AnnX Check = ()
type instance XExpr Check = CheckX type instance XExpr Check = CheckX
type CheckX = CheckXF CheckExpr type CheckX = CheckXF CheckExpr
@ -79,15 +76,15 @@ pattern HoleC = ExprX HoleC_
pattern HoleFC :: CheckExprF r pattern HoleFC :: CheckExprF r
pattern HoleFC = ExprXF HoleC_ pattern HoleFC = ExprXF HoleC_
{-# COMPLETE Var, App, Abs, Let, CtrC, Case, ExprX #-} {-# COMPLETE Var, App, Abs, Let, CtrC, Case, Ann, ExprX #-}
{-# COMPLETE VarF, AppF, AbsF, LetF, CtrFC, CaseF, ExprXF #-} {-# COMPLETE VarF, AppF, AbsF, LetF, CtrFC, CaseF, AnnF, ExprXF #-}
{-# COMPLETE VarF, AppFC, AbsF, LetF, CtrF, CaseF, ExprXF #-} {-# COMPLETE VarF, AppFC, AbsF, LetF, CtrF, CaseF, AnnF, ExprXF #-}
{-# COMPLETE VarF, AppFC, AbsF, LetF, CtrFC, CaseF, ExprXF #-} {-# COMPLETE VarF, AppFC, AbsF, LetF, CtrFC, CaseF, AnnF, ExprXF #-}
{-# COMPLETE Var, App, Abs, Let, Ctr, Case, CallCCC, FixC, HoleC #-} {-# COMPLETE Var, App, Abs, Let, Ctr, Case, Ann, CallCCC, FixC, HoleC #-}
{-# COMPLETE Var, App, Abs, Let, CtrC, Case, CallCCC, FixC, HoleC #-} {-# COMPLETE Var, App, Abs, Let, CtrC, Case, Ann, CallCCC, FixC, HoleC #-}
{-# COMPLETE VarF, AppF, AbsF, LetF, CtrFC, CaseF, CallCCFC, FixFC, HoleFC #-} {-# COMPLETE VarF, AppF, AbsF, LetF, CtrFC, CaseF, AnnF, CallCCFC, FixFC, HoleFC #-}
{-# COMPLETE VarF, AppFC, AbsF, LetF, CtrF, CaseF, CallCCFC, FixFC, HoleFC #-} {-# COMPLETE VarF, AppFC, AbsF, LetF, CtrF, CaseF, AnnF, CallCCFC, FixFC, HoleFC #-}
{-# COMPLETE VarF, AppFC, AbsF, LetF, CtrFC, CaseF, CallCCFC, FixFC, HoleFC #-} {-# COMPLETE VarF, AppFC, AbsF, LetF, CtrFC, CaseF, AnnF, CallCCFC, FixFC, HoleFC #-}
instance RecursivePhase Check where instance RecursivePhase Check where
projectAppArgs = Identity projectAppArgs = Identity
@ -125,66 +122,6 @@ instance Substitutable CheckExpr where
CaseF pats -> Case <$> for pats \(Pat ctr ns e) -> Pat ctr ns <$> maySubstitute ns e CaseF pats -> Case <$> for pats \(Pat ctr ns e) -> Pat ctr ns <$> maySubstitute ns e
e -> embed <$> traverse snd e e -> embed <$> traverse snd e
-- | A monomorphic type.
data Type
-- | Type variable.
= TVar Text
-- | Type application.
| TApp Type Type
-- | The function type.
| TAbs
-- | The product type.
| TProd
-- | The sum type.
| TSum
-- | The unit type.
| TUnit
-- | The empty type.
| TVoid
-- | The type of natural numbers.
| TNat
-- | The type of lists.
| TList
-- | The type of characters.
| TChar
deriving (Eq, Show)
makeBaseFunctor ''Type
instance Substitutable Type where
collectVars withVar _ = cata \case
TVarF n -> withVar n
t -> fold t
-- /All/ variables in a monomorphic type are free.
rename _ t = t
-- No renaming step is necessary.
substitute substs = cata \case
TVarF n -> HM.findWithDefault (TVar n) n substs
e -> embed e
unsafeSubstitute = substitute
-- | A polymorphic type.
data Scheme
-- | Universally quantified type variables.
= TForall [Text] Type
deriving (Eq, Show)
instance Substitutable Scheme where
collectVars withVar withBinder (TForall names t) =
foldMap withBinder names $ collectVars withVar withBinder t
rename = runRenamer \badNames (TForall names t) ->
uncurry TForall <$> replaceNames badNames names (pure t)
-- I took a shot at implementing this but found it to be quite difficult
-- because merging the foralls is tricky.
-- It's not undoable, but it wasn't worth my further time investment
-- seeing as this function isn't currently used anywhere.
unsafeSubstitute = error "Substitution for schemes not yet implemented"
type Substitution = HashMap Text Type type Substitution = HashMap Text Type
type Context = HashMap Text Scheme type Context = HashMap Text Scheme
type Constraint = (Type, Type) type Constraint = (Type, Type)
@ -210,33 +147,3 @@ instance MonoSubstitutable t => MonoSubstitutable [t] where
instance MonoSubstitutable t => MonoSubstitutable (HashMap a t) where instance MonoSubstitutable t => MonoSubstitutable (HashMap a t) where
substituteMono = fmap . substituteMono substituteMono = fmap . substituteMono
tapp :: [Type] -> Type
tapp [] = error "Empty type applications are not permitted"
tapp [t] = t
tapp ts = foldl1' TApp ts
-- HACK
pattern TApp2 :: Type -> Type -> Type -> Type
pattern TApp2 tf tx ty = TApp (TApp tf tx) ty
-- TODO: Improve these printers.
unparseType :: Type -> Text
unparseType (TVar name) = name
unparseType (TApp2 TAbs a b) = "(" <> unparseType a <> " -> " <> unparseType b <> ")"
unparseType (TApp2 TProd a b) = "(" <> unparseType a <> " * " <> unparseType b <> ")"
unparseType (TApp2 TSum a b) = "(" <> unparseType a <> " + " <> unparseType b <> ")"
unparseType (TApp TList a) = "[" <> unparseType a <> "]"
unparseType (TApp a b) = "(" <> unparseType a <> " " <> unparseType b <> ")"
unparseType TAbs = "(->)"
unparseType TProd = "(*)"
unparseType TSum = "(+)"
unparseType TUnit = ""
unparseType TVoid = ""
unparseType TNat = "Nat"
unparseType TList = "[]"
unparseType TChar = "Char"
unparseScheme :: Scheme -> Text
unparseScheme (TForall [] t) = unparseType t
unparseScheme (TForall names t) = "" <> T.unwords names <> ". " <> unparseType t