a type theory with equality based on setoids
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

253 lines
6.5 KiB

{-# LANGUAGE NamedFieldPuns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE DerivingVia #-}
module Elaboration where
import Control.Monad.Except
import Control.Monad.Reader
import Control.Concurrent
import qualified Data.HashMap.Strict as HashMap
import qualified Data.IntMap.Strict as IntMap
import Data.Text (Text)
import Elaboration.Monad
import Evaluate
import Presyntax
import Syntax
import System.IO.Unsafe ( unsafeDupablePerformIO )
import Value
elabNext :: MVar Int
elabNext = unsafeDupablePerformIO (newMVar 0)
{-# NOINLINE elabNext #-}
freshMeta :: Value -> ElabM Term
freshMeta expected = do
ctx <- ask
names <- getNames
thisMeta <- liftIO $ do
m <- modifyMVar elabNext $ \x -> pure (x + 1, x)
modifyMVar_ elabMetas $ pure . IntMap.insert m (Unsolved names expected)
pure m
pure $ NewMeta (MV thisMeta) (elabBound ctx)
insert :: Term -> VTy -> ElabM (Term, VTy)
insert f (VPi Im _ d r) = do
t <- freshMeta d
t_nf <- asks (flip evaluate t . elabEnv)
insert (App Im f t) (r $$ t_nf)
insert f x = pure (f, x)
insert' :: Term -> VTy -> ElabM (Term, VTy)
insert' t@(Lam Im _ _) ty = pure (t, ty)
insert' t ty = insert t ty
infer :: RawExpr -> ElabM (Term, VTy)
infer (RSrcPos start end expr) = local (\st -> st { elabSourcePos = (start, end) }) (infer expr)
infer (Rvar name) = ask >>= lookup where
lookup ElabState{elabNames, elabConstrs, elabLevel} =
case HashMap.lookup name elabNames of
Just (l, t) -> pure (Bv (lvl2Ix elabLevel l), t)
Nothing ->
case HashMap.lookup name elabConstrs of
Just t -> pure (Con name, t)
Nothing -> typeError (NotInScope name)
infer (Rapp p x y) = do
(x, x_ty) <-
infer x >>= \(x, x_ty) ->
case p of
Ex -> insert x x_ty
_ -> pure (x, x_ty)
(_, d, r) <- isPiType p x_ty
y <- check y d
y_nf <- asks (flip evaluate y . elabEnv)
pure (App p x y, r $$ y_nf)
infer (Rpi e v d r) = do
d <- check d VType
d_nf <- asks (flip evaluate d . elabEnv)
assumeLocal v d_nf $ do
r <- check r VType
pure (Pi e v d r, VType)
infer (Rsigma v d r) = do
d <- check d VType
d_nf <- asks (flip evaluate d . elabEnv)
assumeLocal v d_nf $ do
r <- check r VType
pure (Sigma v d r, VType)
infer (Rlet v t d b) = do
t <- check t VType
t_nf <- asks (flip evaluate t . elabEnv)
d <- check d t_nf
d_nf <- asks (flip evaluate d . elabEnv)
defineLocal v t_nf d_nf $ do
(b, ty) <- infer b
pure (Let v t d b, ty)
infer Rtype = pure (Type, VType)
infer Rhole = do
ty <- freshMeta VType
ty_nf <- asks (flip evaluate ty . elabEnv)
tm <- freshMeta ty_nf
pure (tm, ty_nf)
infer (Rlam p v t) = do
env <- asks elabEnv
lvl <- asks elabLevel
dom <- freshMeta VType
let dom_nf = evaluate env dom
assumeLocal v dom_nf $ do
(b, rng) <- infer t
pure (Lam p v b, VPi p v dom_nf (Closure env (quote (succ lvl) rng)))
infer Rtop = pure (Top, VType)
infer Runit = pure (Unit, VTop)
infer (Req a b) = do
t <- freshMeta VType
t_nf <- asks (flip evaluate t . elabEnv)
a <- check a t_nf
b <- check b t_nf
pure (Id t a b, VType)
infer Rrefl =
pure (Refl, forAll Im "A" VType $ \a -> forAll Im "x" a $ \x -> VEq a x x)
infer Rcoe =
pure ( Coe
, forAll Im "A" VType $ \a ->
forAll Im "B" VType $ \b ->
forAll Ex "_" (VEq VType a b) $ \_ ->
forAll Ex "_" a $ const b
)
infer Rcong =
pure ( Cong
, forAll Im "A" VType $ \a ->
forAll Im "B" VType $ \b ->
forAll Im "x" a $ \x ->
forAll Im "y" a $ \y ->
forAll Ex "f" (forAll Ex "_" a (const b)) $ \f ->
forAll Ex "p" (VEq a x y) $ \_ ->
VEq b (vApp f Ex x) (vApp f Ex y)
)
infer Rsym =
pure ( Sym
, forAll Im "A" VType $ \a -> forAll Im "x" a $ \x -> forAll Im "y" a $ \y -> forAll Ex "p" (VEq a x y) $ \_ -> VEq a y x
)
infer (Rproj1 e) = do
(t, ty) <- infer e
(_, d, _) <- isSigmaType ty
pure (Proj1 t, d)
infer (Rproj2 e) = do
(t, ty) <- infer e
t_nf <- asks (flip evaluate t . elabEnv)
(_, _, r) <- isSigmaType ty
pure (Proj2 t, r $$ vProj1 t_nf)
infer c = do
t <- asks elabSwitches
when (t >= 128) $
error $ "Unhandled case in type checker, stack overflew etc: " ++ show c
t <- freshMeta VType
t_nf <- asks (flip evaluate t . elabEnv)
c <- local (\e -> e { elabSwitches = succ (elabSwitches e)}) $
check c t_nf
pure (c, t_nf)
check :: RawExpr -> VTy -> ElabM Term
check (RSrcPos start end expr) ty = local (\st -> st { elabSourcePos = (start, end) }) (check expr ty)
check (Rlam e v t) (VPi e' _ d r) | e == e' = do
level <- asks (unLvl . elabLevel)
assumeLocal v d $
Lam e v <$> check t (r $$ vVar (Bound level))
check t (VPi Im x d r) = do
level <- asks (unLvl . elabLevel)
assumeLocal x d $
Lam Im x <$> check t (r $$ vVar (Bound level))
check (Rlam e v t) ty = do
(_, d, r) <- isPiType e ty
level <- asks (unLvl . elabLevel)
assumeLocal v d $
Lam e v <$> check t (r $$ vVar (Bound level))
check (Rlet v t d b) ty = do
t <- check t VType
t_nf <- asks (flip evaluate t . elabEnv)
d <- check d t_nf
d_nf <- asks (flip evaluate d . elabEnv)
defineLocal v t_nf d_nf $ do
b <- check b ty
pure (Let v t d b)
check (Rpair a b) ty = do
(_, d, r) <- isSigmaType ty
a <- check a d
a_nf <- asks (flip evaluate a . elabEnv)
b <- check b (r $$ a_nf)
pure (Pair a b)
check e ty = do
(new, e_ty) <- uncurry insert =<< infer e
unify e_ty ty
`catchError` \_ -> do
l <- asks elabLevel
names <- getNames
typeError (NotEqual names (quote l (zonk ty)) (quote l (zonk e_ty)))
pure new
isPiType :: Plicity -> VTy -> ElabM (Text, VTy, Closure)
isPiType i = go . force where
go (VPi i' a b c)
| i == i' = pure (a, b, c)
go ty | not (flexible ty) = do
l <- asks elabLevel
names <- getNames
typeError (NotFunction names (quote l ty))
go ty = do
env <- asks elabEnv
t <- freshMeta VType
let t_nf = evaluate env t
assumeLocal "α" t_nf $ do
r <- freshMeta VType
unify ty (VPi i "α" t_nf (Closure env r))
pure ("α", t_nf, Closure env r)
isSigmaType :: VTy -> ElabM (Text, VTy, Closure)
isSigmaType = go . force where
go (VSigma a b c) = pure (a, b, c)
go ty = do
env <- asks elabEnv
t <- freshMeta VType
let t_nf = evaluate env t
assumeLocal "α" t_nf $ do
r <- freshMeta VType
unify ty (VSigma "α" t_nf (Closure env r))
pure ("α", t_nf, Closure env r)