RepLib-0.3: examples/LF.hs
{- Type checker for LF, based on algorithm in Harper and Pfennig, "On
Equivalence and Canonical Forms in the LF Type Theory", ACM
Transactions on Computational Logic, 2000.
-}
{-# LANGUAGE TemplateHaskell
, ScopedTypeVariables
, FlexibleInstances
, MultiParamTypeClasses
, FlexibleContexts
, UndecidableInstances
#-}
module LF where
import Generics.RepLib.Bind.LocallyNameless
import Generics.RepLib
import qualified Data.Set as S
-- Kinds
data Kind = KPi (Bind (Name Tm, Annot Ty) Kind) -- {x:ty} k
| Type -- type
deriving Show
-- Types, also called "Families"
data Ty = TyPi (Bind (Name Tm, Annot Ty) Ty) -- {x:ty} ty
| TyApp Ty Tm -- ty tm
| TyConst (Name Ty) -- a
deriving Show
-- Terms, also called "Objects"
data Tm = Lam (Bind (Name Tm, Annot Ty) Tm) -- [x:ty] tm
| TmApp Tm Tm -- tm tm
| TmVar (Name Tm) -- x
deriving Show
-- Note, Harper and Pfennig distinguish between term variables and
-- constants. Variables are things which can be bound by a lambda
-- or pi; constants are things which are bound in a signature. For
-- our purposes there is little value in distinguishing between
-- them.
$(derive [''Kind, ''Ty, ''Tm])
instance Alpha Kind
instance Alpha Ty
instance Alpha Tm
-- There are no term variables in types or kinds, so we can just
-- use the default structural Subst instances.
instance Subst Tm Kind
instance Subst Tm Ty
-- For Tm we must implement isvar so the Subst instance knows about
-- term variables.
instance Subst Tm Tm where
isvar (TmVar v) = Just (v, id)
isvar _ = Nothing
-- A declaration is either a type constant declaration (a name and a kind)
-- or a term constant declaration (a name, type, and optional definition).
data Decl = DeclTy (Name Ty) (Annot Kind)
| DeclTm (Name Tm) (Annot Ty) (Maybe (Annot Tm)) -- is this right?
-- A program is a sequence of declarations, where each name is bound
-- in the remainder of the program.
data Prog = Nil
| Cons (Bind Decl Prog)
-- A signature is a set of declarations.
type Sig = S.Set Decl