perga/lib/Check.hs

62 lines
2.4 KiB
Haskell
Raw Normal View History

2024-11-17 01:57:53 -08:00
module Check (TypeCheckError (..), CheckResult, checkType) where
2024-10-05 13:31:09 -07:00
2024-11-17 01:57:53 -08:00
import Control.Monad (unless)
2024-11-14 22:02:04 -08:00
import Control.Monad.Except (MonadError (throwError))
2024-11-17 01:57:53 -08:00
import Control.Monad.Reader
import Data.List ((!?))
import qualified Data.Map as M
2024-11-14 22:02:04 -08:00
import Data.Text (Text)
import qualified Data.Text as T
2024-11-11 13:52:50 -08:00
2024-11-17 01:57:53 -08:00
import Eval
2024-11-11 13:37:44 -08:00
import Expr
2024-10-05 13:31:09 -07:00
type Context = [Expr]
2024-11-17 01:57:53 -08:00
data TypeCheckError = SquareUntyped | UnboundVariable Text | NotASort Expr Expr | ExpectedPiType Expr Expr | NotEquivalent Expr Expr Expr deriving (Eq, Ord)
2024-11-12 00:00:51 -08:00
instance Show TypeCheckError where
show SquareUntyped = "□ does not have a type"
2024-11-14 22:02:04 -08:00
show (UnboundVariable x) = "Unbound variable: " ++ T.unpack x
show (NotASort x t) = "Expected " ++ prettyS x ++ " to have type * or □, instead found " ++ prettyS t
show (ExpectedPiType m a) = prettyS m ++ " : " ++ prettyS a ++ " is not a function"
show (NotEquivalent a a' e) = "Cannot unify " ++ prettyS a ++ " with " ++ prettyS a' ++ " when evaluating " ++ prettyS e
2024-11-11 17:57:14 -08:00
type CheckResult = Either TypeCheckError
2024-11-17 01:57:53 -08:00
matchPi :: Expr -> Expr -> ReaderT Env CheckResult (Expr, Expr)
matchPi _ (Pi _ a b) = pure (a, b)
matchPi m e = throwError $ ExpectedPiType m e
2024-11-11 17:57:14 -08:00
2024-11-17 01:57:53 -08:00
findType :: Context -> Expr -> ReaderT Env CheckResult Expr
findType _ Star = pure Square
findType _ Square = throwError SquareUntyped
2024-11-12 00:00:51 -08:00
findType g (Var n x) = do
2024-11-17 01:57:53 -08:00
t <- maybe (throwError $ UnboundVariable x) pure $ g !? fromInteger n
2024-11-11 17:57:14 -08:00
s <- findType g t
2024-11-12 00:00:51 -08:00
unless (isSort s) $ throwError $ NotASort t s
2024-11-11 13:37:44 -08:00
pure t
2024-11-17 01:57:53 -08:00
findType g (Free n) = asks (M.lookup n) >>= maybe (throwError $ UnboundVariable n) (findType g)
2024-11-12 00:00:51 -08:00
findType g e@(App m n) = do
(a, b) <- findType g m >>= matchPi m
2024-11-11 13:37:44 -08:00
a' <- findType g n
2024-11-17 01:57:53 -08:00
equiv <- asks $ runReader (betaEquiv a a')
unless equiv $ throwError $ NotEquivalent a a' e
pure $ subst 0 n b
2024-11-11 17:57:14 -08:00
findType g (Abs x a m) = do
s1 <- findType g a
2024-11-12 00:00:51 -08:00
unless (isSort s1) $ throwError $ NotASort a s1
2024-11-11 17:57:14 -08:00
b <- findType (incIndices a : map incIndices g) m
s2 <- findType g (Pi x a b)
2024-11-12 00:00:51 -08:00
unless (isSort s2) $ throwError $ NotASort (Pi x a b) s2
2024-11-11 17:57:14 -08:00
pure $ if occursFree 0 b then Pi x a b else Pi "" a b
findType g (Pi _ a b) = do
s1 <- findType g a
2024-11-12 00:00:51 -08:00
unless (isSort s1) $ throwError $ NotASort a s1
2024-11-11 17:57:14 -08:00
s2 <- findType (incIndices a : map incIndices g) b
2024-11-12 00:00:51 -08:00
unless (isSort s2) $ throwError $ NotASort b s2
2024-11-11 17:57:14 -08:00
pure s2
2024-11-17 01:57:53 -08:00
checkType :: Env -> Context -> Expr -> CheckResult Expr
checkType env g t = runReaderT (findType g t) env