basics of definitions!!!!

This commit is contained in:
William Ball 2024-11-17 01:57:53 -08:00
parent f5e79c3225
commit c1ccd50644
11 changed files with 159 additions and 127 deletions

View file

@ -1,8 +1,6 @@
module Main where module Main where
import Check
import qualified Data.Text.IO as T import qualified Data.Text.IO as T
import Expr
import Parser import Parser
import Repl import Repl
import System.Environment import System.Environment
@ -23,8 +21,4 @@ handleFile fileName =
input <- T.hGetContents fileH input <- T.hGetContents fileH
case pAll input of case pAll input of
Left err -> putStrLn err Left err -> putStrLn err
Right expr -> case findType [] expr of Right () -> putStrLn "success!"
Left err -> print err
Right ty -> do
putStrLn $ "expr:\t" ++ prettyS expr
putStrLn $ "type:\t" ++ prettyS ty

View file

@ -2,6 +2,7 @@ module Repl (repl) where
import Check import Check
import qualified Data.Text as T import qualified Data.Text as T
import qualified Data.Map as M
import Expr import Expr
import Parser import Parser
import System.Console.Haskeline import System.Console.Haskeline
@ -23,12 +24,7 @@ parseCommand (Just input) = Just (Input input)
handleInput :: ReplState -> String -> InputT IO () handleInput :: ReplState -> String -> InputT IO ()
handleInput state input = case pAll (T.pack input) of handleInput state input = case pAll (T.pack input) of
Left err -> outputStrLn err Left err -> outputStrLn err
Right expr -> case findType [] expr of Right () -> pure ()
Left err -> outputStrLn $ show err
Right ty ->
if debugMode state
then printDebugInfo expr ty
else outputStrLn $ prettyS ty
printDebugInfo :: Expr -> Expr -> InputT IO () printDebugInfo :: Expr -> Expr -> InputT IO ()
printDebugInfo expr ty = do printDebugInfo expr ty = do

View file

@ -24,13 +24,15 @@ build-type: Simple
extra-doc-files: CHANGELOG.md extra-doc-files: CHANGELOG.md
, README.md , README.md
-- Extra source files to be distributed with the package, such as examples, or a tutorial module. common warnings
-- extra-source-files: ghc-options: -Wall
library dependent-lambda-lib library dependent-lambda-lib
import: warnings
exposed-modules: Check exposed-modules: Check
Parser Parser
Expr Expr
Eval
hs-source-dirs: lib hs-source-dirs: lib
build-depends: base ^>=4.19.1.0 build-depends: base ^>=4.19.1.0
@ -38,13 +40,11 @@ library dependent-lambda-lib
, text , text
, parser-combinators , parser-combinators
, mtl , mtl
, containers
default-language: Haskell2010 default-language: Haskell2010
default-extensions: OverloadedStrings default-extensions: OverloadedStrings
, GADTs , GADTs
common warnings
ghc-options: -Wall
executable dependent-lambda executable dependent-lambda
import: warnings import: warnings
main-is: Main.hs main-is: Main.hs
@ -53,6 +53,7 @@ executable dependent-lambda
build-depends: base ^>=4.19.1.0 build-depends: base ^>=4.19.1.0
, dependent-lambda-lib , dependent-lambda-lib
, text , text
, containers
, haskeline , haskeline
, directory , directory
, filepath , filepath
@ -62,6 +63,7 @@ executable dependent-lambda
, GADTs , GADTs
test-suite tests test-suite tests
import: warnings
type: exitcode-stdio-1.0 type: exitcode-stdio-1.0
main-is: Tests.hs main-is: Tests.hs
other-modules: ExprTests other-modules: ExprTests
@ -70,6 +72,7 @@ test-suite tests
build-depends: base ^>=4.19.1.0 build-depends: base ^>=4.19.1.0
, HUnit , HUnit
, text , text
, containers
, dependent-lambda-lib , dependent-lambda-lib
hs-source-dirs: tests hs-source-dirs: tests
default-language: Haskell2010 default-language: Haskell2010

View file

@ -1,16 +1,19 @@
module Check (TypeCheckError (..), CheckResult (..), findType) where module Check (TypeCheckError (..), CheckResult, checkType) where
import Control.Monad (unless)
import Control.Monad.Except (MonadError (throwError)) import Control.Monad.Except (MonadError (throwError))
import Data.List (intercalate, (!?)) import Control.Monad.Reader
import Data.List ((!?))
import qualified Data.Map as M
import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as T import qualified Data.Text as T
import Control.Monad (unless) import Eval
import Expr import Expr
type Context = [Expr] type Context = [Expr]
data TypeCheckError = SquareUntyped | UnboundVariable Text | NotASort Expr Expr | ExpectedPiType Expr Expr | NotEquivalent Expr Expr Expr deriving (Eq) data TypeCheckError = SquareUntyped | UnboundVariable Text | NotASort Expr Expr | ExpectedPiType Expr Expr | NotEquivalent Expr Expr Expr deriving (Eq, Ord)
instance Show TypeCheckError where instance Show TypeCheckError where
show SquareUntyped = "□ does not have a type" show SquareUntyped = "□ does not have a type"
@ -21,25 +24,24 @@ instance Show TypeCheckError where
type CheckResult = Either TypeCheckError type CheckResult = Either TypeCheckError
matchPi :: Expr -> Expr -> CheckResult (Expr, Expr) matchPi :: Expr -> Expr -> ReaderT Env CheckResult (Expr, Expr)
matchPi _ (Pi _ a b) = Right (a, b) matchPi _ (Pi _ a b) = pure (a, b)
matchPi m e = Left $ ExpectedPiType m e matchPi m e = throwError $ ExpectedPiType m e
showContext :: Context -> String findType :: Context -> Expr -> ReaderT Env CheckResult Expr
showContext g = "[" ++ intercalate ", " (map show g) ++ "]" findType _ Star = pure Square
findType _ Square = throwError SquareUntyped
findType :: Context -> Expr -> CheckResult Expr
findType _ Star = Right Square
findType _ Square = Left SquareUntyped
findType g (Var n x) = do findType g (Var n x) = do
t <- maybe (Left $ UnboundVariable x) Right $ g !? fromInteger n t <- maybe (throwError $ UnboundVariable x) pure $ g !? fromInteger n
s <- findType g t s <- findType g t
unless (isSort s) $ throwError $ NotASort t s unless (isSort s) $ throwError $ NotASort t s
pure t pure t
findType g (Free n) = asks (M.lookup n) >>= maybe (throwError $ UnboundVariable n) (findType g)
findType g e@(App m n) = do findType g e@(App m n) = do
(a, b) <- findType g m >>= matchPi m (a, b) <- findType g m >>= matchPi m
a' <- findType g n a' <- findType g n
unless (betaEquiv a a') $ throwError $ NotEquivalent a a' e equiv <- asks $ runReader (betaEquiv a a')
unless equiv $ throwError $ NotEquivalent a a' e
pure $ subst 0 n b pure $ subst 0 n b
findType g (Abs x a m) = do findType g (Abs x a m) = do
s1 <- findType g a s1 <- findType g a
@ -54,3 +56,6 @@ findType g (Pi _ a b) = do
s2 <- findType (incIndices a : map incIndices g) b s2 <- findType (incIndices a : map incIndices g) b
unless (isSort s2) $ throwError $ NotASort b s2 unless (isSort s2) $ throwError $ NotASort b s2
pure s2 pure s2
checkType :: Env -> Context -> Expr -> CheckResult Expr
checkType env g t = runReaderT (findType g t) env

39
lib/Eval.hs Normal file
View file

@ -0,0 +1,39 @@
module Eval where
import Control.Monad.Reader
import qualified Data.Map as M
import Data.Maybe
import Data.Text (Text)
import Expr
type Env = M.Map Text Expr
-- substitute s for k *AND* decrement indices; only use after reducing a redex.
subst :: Integer -> Expr -> Expr -> Expr
subst k s (Var n x)
| k == n = s
| n > k = Var (n - 1) x
| otherwise = Var n x
subst _ _ (Free s) = Free s
subst _ _ Star = Star
subst _ _ Square = Square
subst k s (App m n) = App (subst k s m) (subst k s n)
subst k s (Abs x m n) = Abs x (subst k s m) (subst (k + 1) (incIndices s) n)
subst k s (Pi x m n) = Pi x (subst k s m) (subst (k + 1) (incIndices s) n)
whnf :: Expr -> Expr
whnf (App (Abs _ _ v) n) = whnf $ subst 0 n v
whnf e = e
betaEquiv :: Expr -> Expr -> Reader Env Bool
betaEquiv e1 e2
| e1 == e2 = pure True
| otherwise = case (whnf e1, whnf e2) of
(Var k1 _, Var k2 _) -> pure $ k1 == k2
(Free n, Free m) -> pure $ n == m
(Free n, e) -> fromMaybe False <$> (asks (M.lookup n) >>= traverse (`betaEquiv` e))
(e, Free n) -> fromMaybe False <$> (asks (M.lookup n) >>= traverse (`betaEquiv` e))
(Star, Star) -> pure True
(Abs _ t1 v1, Abs _ t2 v2) -> (&&) <$> betaEquiv t1 t2 <*> betaEquiv v1 v2 -- i want idiom brackets
(Pi _ t1 v1, Pi _ t2 v2) -> (&&) <$> betaEquiv t1 t2 <*> betaEquiv v1 v2
_ -> pure False -- remaining cases impossible or false

View file

@ -6,12 +6,13 @@ import qualified Data.Text as T
data Expr where data Expr where
Var :: Integer -> Text -> Expr Var :: Integer -> Text -> Expr
Free :: Text -> Expr
Star :: Expr Star :: Expr
Square :: Expr Square :: Expr
App :: Expr -> Expr -> Expr App :: Expr -> Expr -> Expr
Abs :: Text -> Expr -> Expr -> Expr Abs :: Text -> Expr -> Expr -> Expr
Pi :: Text -> Expr -> Expr -> Expr Pi :: Text -> Expr -> Expr -> Expr
deriving (Show) deriving (Show, Ord)
instance Eq Expr where instance Eq Expr where
(Var n _) == (Var m _) = n == m (Var n _) == (Var m _) = n == m
@ -24,12 +25,32 @@ instance Eq Expr where
occursFree :: Integer -> Expr -> Bool occursFree :: Integer -> Expr -> Bool
occursFree n (Var k _) = n == k occursFree n (Var k _) = n == k
occursFree _ (Free _) = False
occursFree _ Star = False occursFree _ Star = False
occursFree _ Square = False occursFree _ Square = False
occursFree n (App a b) = on (||) (occursFree n) a b occursFree n (App a b) = on (||) (occursFree n) a b
occursFree n (Abs _ a b) = occursFree n a || occursFree (n + 1) b occursFree n (Abs _ a b) = occursFree n a || occursFree (n + 1) b
occursFree n (Pi _ a b) = occursFree n a || occursFree (n + 1) b occursFree n (Pi _ a b) = occursFree n a || occursFree (n + 1) b
isSort :: Expr -> Bool
isSort Star = True
isSort Square = True
isSort _ = False
shiftIndices :: Integer -> Integer -> Expr -> Expr
shiftIndices d c (Var k x)
| k >= c = Var (k + d) x
| otherwise = Var k x
shiftIndices _ _ (Free s) = Free s
shiftIndices _ _ Star = Star
shiftIndices _ _ Square = Square
shiftIndices d c (App m n) = App (shiftIndices d c m) (shiftIndices d c n)
shiftIndices d c (Abs x m n) = Abs x (shiftIndices d c m) (shiftIndices d (c + 1) n)
shiftIndices d c (Pi x m n) = Pi x (shiftIndices d c m) (shiftIndices d (c + 1) n)
incIndices :: Expr -> Expr
incIndices = shiftIndices 1 0
{- --------------------- PRETTY PRINTING ----------------------------- -} {- --------------------- PRETTY PRINTING ----------------------------- -}
parenthesize :: Text -> Text parenthesize :: Text -> Text
@ -62,6 +83,7 @@ showParamGroup (ids, ty) = parenthesize $ T.unwords ids <> " : " <> pretty ty
helper :: Integer -> Expr -> Text helper :: Integer -> Expr -> Text
helper _ (Var _ s) = s helper _ (Var _ s) = s
helper _ (Free s) = s
helper _ Star = "*" helper _ Star = "*"
helper _ Square = "" helper _ Square = ""
helper k (App e1 e2) = if k > 3 then parenthesize res else res helper k (App e1 e2) = if k > 3 then parenthesize res else res
@ -86,63 +108,3 @@ pretty = helper 0
prettyS :: Expr -> String prettyS :: Expr -> String
prettyS = T.unpack . pretty prettyS = T.unpack . pretty
{- --------------- ACTUAL MATH STUFF ---------------- -}
isSort :: Expr -> Bool
isSort Star = True
isSort Square = True
isSort _ = False
shiftIndices :: Integer -> Integer -> Expr -> Expr
shiftIndices d c (Var k x)
| k >= c = Var (k + d) x
| otherwise = Var k x
shiftIndices _ _ Star = Star
shiftIndices _ _ Square = Square
shiftIndices d c (App m n) = App (shiftIndices d c m) (shiftIndices d c n)
shiftIndices d c (Abs x m n) = Abs x (shiftIndices d c m) (shiftIndices d (c + 1) n)
shiftIndices d c (Pi x m n) = Pi x (shiftIndices d c m) (shiftIndices d (c + 1) n)
incIndices :: Expr -> Expr
incIndices = shiftIndices 1 0
-- substitute s for k *AND* decrement indices; only use after reducing a redex.
subst :: Integer -> Expr -> Expr -> Expr
subst k s (Var n x)
| k == n = s
| n > k = Var (n - 1) x
| otherwise = Var n x
subst _ _ Star = Star
subst _ _ Square = Square
subst k s (App m n) = App (subst k s m) (subst k s n)
subst k s (Abs x m n) = Abs x (subst k s m) (subst (k + 1) (incIndices s) n)
subst k s (Pi x m n) = Pi x (subst k s m) (subst (k + 1) (incIndices s) n)
betaReduce :: Expr -> Expr
betaReduce (Var k s) = Var k s
betaReduce Star = Star
betaReduce Square = Square
betaReduce (App (Abs _ _ v) n) = subst 0 n v
betaReduce (App m n) = App (betaReduce m) (betaReduce n)
betaReduce (Abs x t v) = Abs x (betaReduce t) (betaReduce v)
betaReduce (Pi x t v) = Pi x (betaReduce t) (betaReduce v)
betaNF :: Expr -> Expr
betaNF e = if e == e' then e else betaNF e'
where
e' = betaReduce e
whnf :: Expr -> Expr
whnf (App (Abs _ _ v) n) = whnf $ subst 0 n v
whnf e = e
betaEquiv :: Expr -> Expr -> Bool
betaEquiv e1 e2
| e1 == e2 = True
| otherwise = case (whnf e1, whnf e2) of
(Var k1 _, Var k2 _) -> k1 == k2
(Star, Star) -> True
(Abs _ t1 v1, Abs _ t2 v2) -> betaEquiv t1 t2 && betaEquiv v1 v2
(Pi _ t1 v1, Pi _ t2 v2) -> betaEquiv t1 t2 && betaEquiv v1 v2
_ -> False -- remaining cases impossible or false

View file

@ -1,5 +1,8 @@
{-# LANGUAGE NamedFieldPuns #-}
module Parser (pAll) where module Parser (pAll) where
import Check
import Control.Monad import Control.Monad
import Control.Monad.State.Strict import Control.Monad.State.Strict
import Data.Bifunctor (first) import Data.Bifunctor (first)
@ -7,22 +10,30 @@ import Data.Functor.Identity
import Data.List (elemIndex) import Data.List (elemIndex)
import Data.List.NonEmpty (NonEmpty ((:|))) import Data.List.NonEmpty (NonEmpty ((:|)))
import qualified Data.List.NonEmpty as NE import qualified Data.List.NonEmpty as NE
import qualified Data.Map as M
import Data.Text (Text) import Data.Text (Text)
import qualified Data.Text as T import qualified Data.Text as T
import Eval
import Expr (Expr (..), incIndices) import Expr (Expr (..), incIndices)
import Text.Megaparsec hiding (State) import Text.Megaparsec hiding (State)
import Text.Megaparsec.Char import Text.Megaparsec.Char
import qualified Text.Megaparsec.Char.Lexer as L import qualified Text.Megaparsec.Char.Lexer as L
type InnerState = [Text] data InnerState = IS {_binds :: [Text], _defs :: Env}
data CustomErrors = UnboundVariable Text [Text] deriving (Eq, Ord, Show) newtype TypeError = TE TypeCheckError
deriving (Eq, Ord, Show)
instance ShowErrorComponent CustomErrors where type Parser = ParsecT TypeError Text (State InnerState)
showErrorComponent (UnboundVariable var bound) =
"Unbound variable: " ++ T.unpack var ++ ". Did you mean one of: " ++ T.unpack (T.unwords bound) ++ "?"
type Parser = ParsecT CustomErrors Text (State InnerState) instance ShowErrorComponent TypeError where
showErrorComponent (TE e) = show e
bindsToIS :: ([Text] -> [Text]) -> InnerState -> InnerState
bindsToIS f x@(IS{_binds}) = x{_binds = f _binds}
defsToIS :: (Env -> Env) -> InnerState -> InnerState
defsToIS f x@(IS{_defs}) = x{_defs = f _defs}
skipSpace :: Parser () skipSpace :: Parser ()
skipSpace = skipSpace =
@ -38,15 +49,15 @@ pIdentifier :: Parser Text
pIdentifier = label "identifier" $ lexeme $ do pIdentifier = label "identifier" $ lexeme $ do
firstChar <- letterChar <|> char '_' firstChar <- letterChar <|> char '_'
rest <- many $ alphaNumChar <|> char '_' rest <- many $ alphaNumChar <|> char '_'
return $ T.pack (firstChar : rest) -- Still need T.pack here as we're building from chars return $ T.pack (firstChar : rest)
pVar :: Parser Expr pVar :: Parser Expr
pVar = label "variable" $ lexeme $ do pVar = label "variable" $ lexeme $ do
var <- pIdentifier var <- pIdentifier
binders <- get binders <- _binds <$> get
case elemIndex var binders of pure $ case elemIndex var binders of
Just i -> return $ Var (fromIntegral i) var Just i -> Var (fromIntegral i) var
Nothing -> customFailure $ UnboundVariable var binders Nothing -> Free var
defChoice :: NE.NonEmpty Text -> Parser () defChoice :: NE.NonEmpty Text -> Parser ()
defChoice options = lexeme $ label (T.unpack $ NE.head options) $ void $ choice $ NE.map chunk options defChoice options = lexeme $ label (T.unpack $ NE.head options) $ void $ choice $ NE.map chunk options
@ -56,7 +67,7 @@ pParamGroup = lexeme $ label "parameter group" $ between (char '(') (char ')') $
idents <- some pIdentifier idents <- some pIdentifier
_ <- defChoice $ ":" :| [] _ <- defChoice $ ":" :| []
ty <- pExpr ty <- pExpr
modify (flip (foldl $ flip (:)) idents) modify $ bindsToIS $ flip (foldl $ flip (:)) idents
pure $ zip idents (iterate incIndices ty) pure $ zip idents (iterate incIndices ty)
pParams :: Parser [(Text, Expr)] pParams :: Parser [(Text, Expr)]
@ -68,7 +79,7 @@ pLAbs = lexeme $ label "λ-abstraction" $ do
params <- pParams params <- pParams
_ <- defChoice $ "." :| ["=>", ""] _ <- defChoice $ "." :| ["=>", ""]
body <- pExpr body <- pExpr
modify (drop $ length params) modify $ bindsToIS $ drop $ length params
pure $ foldr (uncurry Abs) body params pure $ foldr (uncurry Abs) body params
pPAbs :: Parser Expr pPAbs :: Parser Expr
@ -77,7 +88,7 @@ pPAbs = lexeme $ label "Π-abstraction" $ do
params <- pParams params <- pParams
_ <- defChoice $ "." :| [","] _ <- defChoice $ "." :| [","]
body <- pExpr body <- pExpr
modify (drop $ length params) modify $ bindsToIS $ drop $ length params
pure $ foldr (uncurry Pi) body params pure $ foldr (uncurry Pi) body params
pArrow :: Parser Expr pArrow :: Parser Expr
@ -112,5 +123,20 @@ pAppTerm = lexeme $ pLAbs <|> pPAbs <|> pApp
pExpr :: Parser Expr pExpr :: Parser Expr
pExpr = lexeme $ try pArrow <|> pAppTerm pExpr = lexeme $ try pArrow <|> pAppTerm
pAll :: Text -> Either String Expr pDef :: Parser ()
pAll input = first errorBundlePretty $ fst $ runIdentity $ runStateT (runParserT pExpr "" input) [] pDef = lexeme $ label "definition" $ do
ident <- pIdentifier
_ <- defChoice $ ":=" :| []
value <- pExpr
_ <- defChoice $ ";" :| []
foo <- get
let ty = checkType (_defs foo) [] value
case ty of
Left err -> customFailure $ TE err
Right _ -> modify $ defsToIS $ M.insert ident value
pProgram :: Parser ()
pProgram = void $ many pDef
pAll :: Text -> Either String ()
pAll input = first errorBundlePretty $ fst $ runIdentity $ runStateT (runParserT pProgram "" input) $ IS{_binds = [], _defs = M.empty}

2
test.pg Normal file
View file

@ -0,0 +1,2 @@
id := fun (A : *) (x : A) . x ;
foo := fun (A B : *) (f : A -> B) (x : A) . id (A -> B) f (id A x) ;

View file

@ -1,11 +1,12 @@
module CheckTests (tests) where module CheckTests (tests) where
import Check import Check
import qualified Data.Map as M
import Expr (Expr (..)) import Expr (Expr (..))
import Test.HUnit import Test.HUnit
sort :: Test sort :: Test
sort = TestCase $ assertEqual "*" (Right Square) (findType [] Star) sort = TestCase $ assertEqual "*" (Right Square) (checkType M.empty [] Star)
stlc :: Test stlc :: Test
stlc = stlc =
@ -13,7 +14,12 @@ stlc =
assertEqual assertEqual
"fun (x : A) (y : B) . x" "fun (x : A) (y : B) . x"
(Right $ Pi "" (Var 0 "A") (Pi "" (Var 2 "B") (Var 2 "A"))) (Right $ Pi "" (Var 0 "A") (Pi "" (Var 2 "B") (Var 2 "A")))
(findType [Star, Star] $ Abs "x" (Var 0 "A") (Abs "y" (Var 2 "B") (Var 1 "x"))) (checkType M.empty [Star, Star] $ Abs "x" (Var 0 "A") (Abs "y" (Var 2 "B") (Var 1 "x")))
freeVar :: Test
freeVar =
TestCase $
assertEqual "{x = *} , [] |- x : □" (Right Square) (checkType (M.singleton "x" Star) [] (Free "x"))
polyIdent :: Test polyIdent :: Test
polyIdent = polyIdent =
@ -21,7 +27,7 @@ polyIdent =
assertEqual assertEqual
"fun (A : *) (x : A) . x" "fun (A : *) (x : A) . x"
(Right $ Pi "A" Star (Pi "" (Var 0 "A") (Var 1 "A"))) (Right $ Pi "A" Star (Pi "" (Var 0 "A") (Var 1 "A")))
(findType [] (Abs "A" Star (Abs "x" (Var 0 "A") (Var 0 "x")))) (checkType M.empty [] (Abs "A" Star (Abs "x" (Var 0 "A") (Var 0 "x"))))
typeCons :: Test typeCons :: Test
typeCons = typeCons =
@ -29,7 +35,7 @@ typeCons =
assertEqual assertEqual
"fun (A B : *) . A -> B" "fun (A B : *) . A -> B"
(Right $ Pi "" Star (Pi "" Star Star)) (Right $ Pi "" Star (Pi "" Star Star))
(findType [] (Abs "A" Star (Abs "B" Star (Pi "" (Var 1 "A") (Var 1 "B"))))) (checkType M.empty [] (Abs "A" Star (Abs "B" Star (Pi "" (Var 1 "A") (Var 1 "B")))))
useTypeCons :: Test useTypeCons :: Test
useTypeCons = useTypeCons =
@ -37,7 +43,7 @@ useTypeCons =
assertEqual assertEqual
"fun (C : * -> *) (A : *) (x : C A) . x" "fun (C : * -> *) (A : *) (x : C A) . x"
(Right $ Pi "C" (Pi "" Star Star) (Pi "A" Star (Pi "" (App (Var 1 "C") (Var 0 "A")) (App (Var 2 "C") (Var 1 "A"))))) (Right $ Pi "C" (Pi "" Star Star) (Pi "A" Star (Pi "" (App (Var 1 "C") (Var 0 "A")) (App (Var 2 "C") (Var 1 "A")))))
(findType [] $ Abs "C" (Pi "" Star Star) (Abs "A" Star (Abs "x" (App (Var 1 "C") (Var 0 "A")) (Var 0 "x")))) (checkType M.empty [] $ Abs "C" (Pi "" Star Star) (Abs "A" Star (Abs "x" (App (Var 1 "C") (Var 0 "A")) (Var 0 "x"))))
dependent :: Test dependent :: Test
dependent = dependent =
@ -45,7 +51,7 @@ dependent =
assertEqual assertEqual
"fun (S : *) (x : S) . S -> S" "fun (S : *) (x : S) . S -> S"
(Right $ Pi "S" Star (Pi "" (Var 0 "S") Star)) (Right $ Pi "S" Star (Pi "" (Var 0 "S") Star))
(findType [] $ Abs "S" Star (Abs "x" (Var 0 "S") (Pi "" (Var 1 "S") (Var 2 "S")))) (checkType M.empty [] $ Abs "S" Star (Abs "x" (Var 0 "S") (Pi "" (Var 1 "S") (Var 2 "S"))))
useDependent :: Test useDependent :: Test
useDependent = useDependent =
@ -53,7 +59,7 @@ useDependent =
assertEqual assertEqual
"fun (S : *) (P : S -> *) (x : S) . P x" "fun (S : *) (P : S -> *) (x : S) . P x"
(Right $ Pi "S" Star (Pi "" (Pi "" (Var 0 "S") Star) (Pi "" (Var 1 "S") Star))) (Right $ Pi "S" Star (Pi "" (Pi "" (Var 0 "S") Star) (Pi "" (Var 1 "S") Star)))
(findType [] $ Abs "S" Star (Abs "P" (Pi "" (Var 0 "S") Star) (Abs "x" (Var 1 "S") (App (Var 1 "P") (Var 0 "x"))))) (checkType M.empty [] $ Abs "S" Star (Abs "P" (Pi "" (Var 0 "S") Star) (Abs "x" (Var 1 "S") (App (Var 1 "P") (Var 0 "x")))))
big :: Test big :: Test
big = big =
@ -61,15 +67,15 @@ big =
assertEqual assertEqual
"fun (S : *) (P Q : S -> *) (H : forall (x : S), P x -> Q x) (G : forall (x : S), P x) (x : S) . H x (G x)" "fun (S : *) (P Q : S -> *) (H : forall (x : S), P x -> Q x) (G : forall (x : S), P x) (x : S) . H x (G x)"
(Right $ Pi "S" Star (Pi "P" (Pi "" (Var 0 "S") Star) (Pi "Q" (Pi "" (Var 1 "S") Star) (Pi "" (Pi "x" (Var 2 "S") (Pi "" (App (Var 2 "P") (Var 0 "x")) (App (Var 2 "Q") (Var 1 "x")))) (Pi "" (Pi "x" (Var 3 "S") (App (Var 3 "P") (Var 0 "x"))) (Pi "x" (Var 4 "S") (App (Var 3 "Q") (Var 0 "x")))))))) (Right $ Pi "S" Star (Pi "P" (Pi "" (Var 0 "S") Star) (Pi "Q" (Pi "" (Var 1 "S") Star) (Pi "" (Pi "x" (Var 2 "S") (Pi "" (App (Var 2 "P") (Var 0 "x")) (App (Var 2 "Q") (Var 1 "x")))) (Pi "" (Pi "x" (Var 3 "S") (App (Var 3 "P") (Var 0 "x"))) (Pi "x" (Var 4 "S") (App (Var 3 "Q") (Var 0 "x"))))))))
(findType [] $ Abs "S" Star (Abs "P" (Pi "" (Var 0 "S") Star) (Abs "Q" (Pi "" (Var 1 "S") Star) (Abs "H" (Pi "x" (Var 2 "S") (Pi "" (App (Var 2 "P") (Var 0 "x")) (App (Var 2 "Q") (Var 1 "x")))) (Abs "G" (Pi "x" (Var 3 "S") (App (Var 3 "P") (Var 0 "x"))) (Abs "x" (Var 4 "S") (App (App (Var 2 "H") (Var 0 "x")) (App (Var 1 "G") (Var 0 "x"))))))))) (checkType M.empty [] $ Abs "S" Star (Abs "P" (Pi "" (Var 0 "S") Star) (Abs "Q" (Pi "" (Var 1 "S") Star) (Abs "H" (Pi "x" (Var 2 "S") (Pi "" (App (Var 2 "P") (Var 0 "x")) (App (Var 2 "Q") (Var 1 "x")))) (Abs "G" (Pi "x" (Var 3 "S") (App (Var 3 "P") (Var 0 "x"))) (Abs "x" (Var 4 "S") (App (App (Var 2 "H") (Var 0 "x")) (App (Var 1 "G") (Var 0 "x")))))))))
tests :: Test tests :: Test
tests = tests =
TestList TestList
[ TestLabel "sort" sort [ TestLabel "sort" sort
, TestLabel "λ→" stlc , TestLabel "λ→" $ TestList [stlc, freeVar]
, TestLabel "λ2" polyIdent , TestLabel "λ2" polyIdent
, TestLabel "λω" (TestList [typeCons, useTypeCons]) , TestLabel "λω" $ TestList [typeCons, useTypeCons]
, TestLabel "λP2" (TestList [dependent, useDependent]) , TestLabel "λP2" $ TestList [dependent, useDependent]
, TestLabel "λC" big , TestLabel "λC" big
] ]

View file

@ -1,6 +1,7 @@
module ExprTests (tests) where module ExprTests (tests) where
import Expr import Expr
import Eval
import Test.HUnit import Test.HUnit
inner :: Expr inner :: Expr
@ -34,13 +35,13 @@ substE1 =
after after
(subst 0 (Var 2 "B") inner) (subst 0 (Var 2 "B") inner)
betaNFe1 :: Test whnfE1 :: Test
betaNFe1 = whnfE1 =
TestCase $ TestCase $
assertEqual assertEqual
"e1 B" "e1 B"
after after
(betaNF $ App e1 $ Var 2 "B") (whnf $ App e1 $ Var 2 "B")
tests :: Test tests :: Test
tests = tests =
@ -48,5 +49,5 @@ tests =
[ TestLabel "fFree" fFree [ TestLabel "fFree" fFree
, TestLabel "incE1" incE1 , TestLabel "incE1" incE1
, TestLabel "substE1" substE1 , TestLabel "substE1" substE1
, TestLabel "betaNFe1" betaNFe1 , TestLabel "whnfE1" whnfE1
] ]

View file

@ -1,7 +1,5 @@
module ParserTests (tests) where module ParserTests (tests) where
import Data.Text (Text)
import qualified Data.Text as T
import Expr (Expr (..)) import Expr (Expr (..))
import Parser (pAll) import Parser (pAll)
import Test.HUnit import Test.HUnit