{-# LANGUAGE TemplateHaskell, ScopedTypeVariables, FlexibleInstances, MultiParamTypeClasses, FlexibleContexts, UndecidableInstances, GADTs #-} module F where import Unbound.LocallyNameless import Control.Monad import Control.Monad.Trans.Error import Data.List as List -- System F with type and term variables type TyName = Name Ty type TmName = Name Tm data Ty = TyVar TyName | Arr Ty Ty | All (Bind TyName Ty) deriving Show data Tm = TmVar TmName | Lam (Bind (TmName, Embed Ty) Tm) | TLam (Bind TyName Tm) | App Tm Tm | TApp Tm Ty deriving Show $(derive [''Ty, ''Tm]) ------------------------------------------------------ instance Alpha Ty where instance Alpha Tm where instance Subst Tm Ty where instance Subst Tm Tm where isvar (TmVar x) = Just (SubstName x) isvar _ = Nothing instance Subst Ty Ty where isvar (TyVar x) = Just (SubstName x) isvar _ = Nothing ------------------------------------------------------ -- Example terms ------------------------------------------------------ x :: Name Tm y :: Name Tm z :: Name Tm (x,y,z) = (string2Name "x", string2Name "y", string2Name "z") a :: Name Ty b :: Name Ty c :: Name Ty (a,b,c) = (string2Name "a", string2Name "b", string2Name "c") -- /\a. \x:a. x polyid :: Tm polyid = TLam (bind a (Lam (bind (x, Embed (TyVar a)) (TmVar x)))) -- All a. a -> a polyidty :: Ty polyidty = All (bind a (Arr (TyVar a) (TyVar a))) ----------------------------------------------------------------- -- Typechecker ----------------------------------------------------------------- type Delta = [ TyName ] type Gamma = [ (TmName, Ty) ] data Ctx = Ctx { getDelta :: Delta , getGamma :: Gamma } emptyCtx = Ctx { getDelta = [], getGamma = [] } type M = ErrorT String FreshM runM :: M a -> a runM m = case (runFreshM (runErrorT m)) of Left s -> error s Right a -> a checkTyVar :: Ctx -> TyName -> M () checkTyVar g v = do if List.elem v (getDelta g) then return () else throwError "NotFound" lookupTmVar :: Ctx -> TmName -> M Ty lookupTmVar g v = do case lookup v (getGamma g) of Just s -> return s Nothing -> throwError "NotFound" extendTy :: TyName -> Ctx -> Ctx extendTy n ctx = ctx { getDelta = n : (getDelta ctx) } extendTm :: TmName -> Ty -> Ctx -> Ctx extendTm n ty ctx = ctx { getGamma = (n, ty) : (getGamma ctx) } tcty :: Ctx -> Ty -> M () tcty g (TyVar x) = checkTyVar g x tcty g (All b) = do (x, ty') <- unbind b tcty (extendTy x g) ty' tcty g (Arr t1 t2) = do tcty g t1 tcty g t2 ti :: Ctx -> Tm -> M Ty ti g (TmVar x) = lookupTmVar g x ti g (Lam bnd) = do ((x, Embed ty1), t) <- unbind bnd tcty g ty1 ty2 <- ti (extendTm x ty1 g) t return (Arr ty1 ty2) ti g (App t1 t2) = do ty1 <- ti g t1 ty2 <- ti g t2 case ty1 of Arr ty11 ty21 | ty2 `aeq` ty11 -> return ty21 _ -> throwError "TypeError" ti g (TLam bnd) = do (x, t) <- unbind bnd ty <- ti (extendTy x g) t return (All (bind x ty)) ti g (TApp t ty) = do tyt <- ti g t case tyt of (All b) -> do tcty g ty (n1, ty1) <- unbind b return $ subst n1 ty ty1