Compare commits
No commits in common. "51d97b15f55939f780385ac815af25c1a8bedaaa" and "3715773adc63267ae6e0bd7b152f603cb5bab345" have entirely different histories.
51d97b15f5
...
3715773adc
9 changed files with 73 additions and 171 deletions
|
|
@ -80,11 +80,8 @@ The error messages currently aren't terrible, but it would be nice to have, e.g.
|
||||||
*** TODO Improve β-equivalence check
|
*** TODO Improve β-equivalence check
|
||||||
The check for β-equivalence could certainly be a lot smarter. Right now it just fully normalizes both terms and checks if the normal forms are equal, which isn't the best strategy. This is much less of an issue without [[Inductive Definitions][inductive definitions]]/recursion, as far less computation gets done in general, let alone at the type level. That being said, it's certainly not a bad idea.
|
The check for β-equivalence could certainly be a lot smarter. Right now it just fully normalizes both terms and checks if the normal forms are equal, which isn't the best strategy. This is much less of an issue without [[Inductive Definitions][inductive definitions]]/recursion, as far less computation gets done in general, let alone at the type level. That being said, it's certainly not a bad idea.
|
||||||
|
|
||||||
*** DONE Better testing
|
*** TODO Better testing
|
||||||
Using some kind of testing framework, like [[https://hackage.haskell.org/package/QuickCheck][QuickCheck]] and/or [[https://hackage.haskell.org/package/HUnit][HUnit]] seems like a good idea. I would like to avoid regressions as I keep working on this, and a suite of unit tests would make me feel much more comfortable.
|
Using some kind of testing framework, like [[https://hackage.haskell.org/package/QuickCheck][QuickCheck]] and/or [[https://hackage.haskell.org/package/HUnit][HUnit]] seems like a good idea. I would like to avoid regressions as I keep working on this, and a suite of unit tests would make me feel much more comfortable.
|
||||||
|
|
||||||
*** DONE Switch to =Text=
|
|
||||||
Currently I use =String= everywhere. Switching to =Text= should be straightforward, and would improve performance and Unicode support.
|
|
||||||
|
|
||||||
*** TODO TUI
|
*** TODO TUI
|
||||||
This is definitely a stretch goal, but I'm imagining a TUI split into two panels. On the left you can see the term you are building with holes in it. On the right you have the focused hole's type as well as the types of everything in scope (like Coq and Lean show while you're in the middle of a proof). Then you can interact with the system by entering commands (e.g. =intros=, =apply=, etc.) which changes the proof term on the left. You'd also just be able to type in the left window as well, and edit the proof term directly. This way you'd get the benefits of working with tactics, making it way faster to construct proof terms, and the benefits of working with proof terms directly, namely transparency and simplicity. I'll probably want to look into [[https://hackage.haskell.org/package/brick][brick]] in order to make this happen.
|
This is definitely a stretch goal, but I'm imagining a TUI split into two panels. On the left you can see the term you are building with holes in it. On the right you have the focused hole's type as well as the types of everything in scope (like Coq and Lean show while you're in the middle of a proof). Then you can interact with the system by entering commands (e.g. =intros=, =apply=, etc.) which changes the proof term on the left. You'd also just be able to type in the left window as well, and edit the proof term directly. This way you'd get the benefits of working with tactics, making it way faster to construct proof terms, and the benefits of working with proof terms directly, namely transparency and simplicity. I'll probably want to look into [[https://hackage.haskell.org/package/brick][brick]] in order to make this happen.
|
||||||
|
|
|
||||||
|
|
@ -3,17 +3,16 @@ module Main where
|
||||||
import Check
|
import Check
|
||||||
import Expr
|
import Expr
|
||||||
import Parser
|
import Parser
|
||||||
import qualified Data.Text.IO as T
|
|
||||||
import System.IO
|
import System.IO
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
_ <- T.putStr "> "
|
_ <- putStr "> "
|
||||||
_ <- hFlush stdout
|
_ <- hFlush stdout
|
||||||
input <- T.getLine
|
input <- getLine
|
||||||
case pAll input of
|
case pAll input of
|
||||||
Left err -> T.putStrLn err
|
Left err -> putStrLn err
|
||||||
Right expr -> case findType [] expr of
|
Right expr -> case findType [] expr of
|
||||||
Right ty -> T.putStrLn $ pretty expr <> " : " <> pretty ty
|
Right ty -> putStrLn $ pretty expr ++ " : " ++ pretty ty
|
||||||
Left err -> print err
|
Left err -> print err
|
||||||
main
|
main
|
||||||
|
|
|
||||||
|
|
@ -28,46 +28,38 @@ extra-doc-files: CHANGELOG.md
|
||||||
-- extra-source-files:
|
-- extra-source-files:
|
||||||
|
|
||||||
library dependent-lambda-lib
|
library dependent-lambda-lib
|
||||||
exposed-modules: Check
|
exposed-modules: Check
|
||||||
Parser
|
Parser
|
||||||
Expr
|
Expr
|
||||||
|
|
||||||
hs-source-dirs: lib
|
hs-source-dirs: lib
|
||||||
build-depends: base ^>=4.19.1.0
|
build-depends: base ^>=4.19.1.0
|
||||||
, megaparsec
|
, megaparsec
|
||||||
, text
|
, text
|
||||||
, parser-combinators
|
, parser-combinators
|
||||||
, mtl
|
, mtl
|
||||||
default-language: Haskell2010
|
default-language: Haskell2010
|
||||||
default-extensions: OverloadedStrings
|
|
||||||
, GADTs
|
|
||||||
|
|
||||||
common warnings
|
common warnings
|
||||||
ghc-options: -Wall
|
ghc-options: -Wall
|
||||||
|
|
||||||
executable dependent-lambda
|
executable dependent-lambda
|
||||||
import: warnings
|
import: warnings
|
||||||
main-is: Main.hs
|
main-is: Main.hs
|
||||||
|
|
||||||
build-depends: base ^>=4.19.1.0
|
build-depends: base ^>=4.19.1.0
|
||||||
, dependent-lambda-lib
|
, dependent-lambda-lib
|
||||||
, text
|
hs-source-dirs: app
|
||||||
hs-source-dirs: app
|
default-language: Haskell2010
|
||||||
default-language: Haskell2010
|
|
||||||
default-extensions: OverloadedStrings
|
|
||||||
, GADTs
|
|
||||||
|
|
||||||
test-suite tests
|
test-suite tests
|
||||||
type: exitcode-stdio-1.0
|
type: exitcode-stdio-1.0
|
||||||
main-is: Tests.hs
|
main-is: Tests.hs
|
||||||
other-modules: ExprTests
|
other-modules: ExprTests
|
||||||
, ParserTests
|
, ParserTests
|
||||||
, CheckTests
|
, CheckTests
|
||||||
build-depends: base ^>=4.19.1.0
|
build-depends: base ^>=4.19.1.0
|
||||||
, HUnit
|
, HUnit
|
||||||
, text
|
, dependent-lambda-lib
|
||||||
, dependent-lambda-lib
|
hs-source-dirs: tests
|
||||||
hs-source-dirs: tests
|
default-language: Haskell2010
|
||||||
default-language: Haskell2010
|
|
||||||
default-extensions: OverloadedStrings
|
|
||||||
, GADTs
|
|
||||||
|
|
|
||||||
14
lib/Check.hs
14
lib/Check.hs
|
|
@ -1,23 +1,21 @@
|
||||||
module Check (TypeCheckError (..), CheckResult (..), findType) where
|
module Check (TypeCheckError (..), CheckResult (..), findType) where
|
||||||
|
|
||||||
import Control.Monad.Except (MonadError (throwError))
|
import Control.Monad.Except ( MonadError(throwError) )
|
||||||
import Data.List (intercalate, (!?))
|
import Data.List (intercalate, (!?))
|
||||||
import Data.Text (Text)
|
|
||||||
import qualified Data.Text as T
|
|
||||||
|
|
||||||
import Control.Monad (unless)
|
import Control.Monad (unless)
|
||||||
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 String | NotASort Expr Expr | ExpectedPiType Expr Expr | NotEquivalent Expr Expr Expr
|
||||||
|
|
||||||
instance Show TypeCheckError where
|
instance Show TypeCheckError where
|
||||||
show SquareUntyped = "□ does not have a type"
|
show SquareUntyped = "□ does not have a type"
|
||||||
show (UnboundVariable x) = "Unbound variable: " ++ T.unpack x
|
show (UnboundVariable x) = "Unbound variable: " ++ x
|
||||||
show (NotASort x t) = "Expected " ++ prettyS x ++ " to have type * or □, instead found " ++ prettyS t
|
show (NotASort x t) = "Expected " ++ pretty x ++ " to have type * or □, instead found " ++ pretty t
|
||||||
show (ExpectedPiType m a) = prettyS m ++ " : " ++ prettyS a ++ " is not a function"
|
show (ExpectedPiType m a) = pretty m ++ " : " ++ pretty a ++ " is not a function"
|
||||||
show (NotEquivalent a a' e) = "Cannot unify " ++ prettyS a ++ " with " ++ prettyS a' ++ " when evaluating " ++ prettyS e
|
show (NotEquivalent a a' e) = "Cannot unify " ++ pretty a ++ " with " ++ pretty a' ++ " when evaluating " ++ pretty e
|
||||||
|
|
||||||
type CheckResult = Either TypeCheckError
|
type CheckResult = Either TypeCheckError
|
||||||
|
|
||||||
|
|
|
||||||
41
lib/Expr.hs
41
lib/Expr.hs
|
|
@ -1,16 +1,16 @@
|
||||||
|
{-# LANGUAGE GADTs #-}
|
||||||
|
|
||||||
module Expr where
|
module Expr where
|
||||||
|
|
||||||
import Data.Function (on)
|
import Data.Function (on)
|
||||||
import Data.Text (Text)
|
|
||||||
import qualified Data.Text as T
|
|
||||||
|
|
||||||
data Expr where
|
data Expr where
|
||||||
Var :: Integer -> Text -> Expr
|
Var :: Integer -> String -> Expr
|
||||||
Star :: Expr
|
Star :: Expr
|
||||||
Square :: Expr
|
Square :: Expr
|
||||||
App :: Expr -> Expr -> Expr
|
App :: Expr -> Expr -> Expr
|
||||||
Abs :: Text -> Expr -> Expr -> Expr
|
Abs :: String -> Expr -> Expr -> Expr
|
||||||
Pi :: Text -> Expr -> Expr -> Expr
|
Pi :: String -> Expr -> Expr -> Expr
|
||||||
deriving (Show)
|
deriving (Show)
|
||||||
|
|
||||||
instance Eq Expr where
|
instance Eq Expr where
|
||||||
|
|
@ -32,61 +32,58 @@ occursFree n (Pi _ a b) = occursFree n a || occursFree (n + 1) b
|
||||||
|
|
||||||
{- --------------------- PRETTY PRINTING ----------------------------- -}
|
{- --------------------- PRETTY PRINTING ----------------------------- -}
|
||||||
|
|
||||||
parenthesize :: Text -> Text
|
parenthesize :: String -> String
|
||||||
parenthesize s = T.concat ["(", s, ")"]
|
parenthesize s = "(" ++ s ++ ")"
|
||||||
|
|
||||||
collectLambdas :: Expr -> ([(Text, Expr)], Expr)
|
collectLambdas :: Expr -> ([(String, Expr)], Expr)
|
||||||
collectLambdas (Abs x ty body) = ((x, ty) : params, final)
|
collectLambdas (Abs x ty body) = ((x, ty) : params, final)
|
||||||
where
|
where
|
||||||
(params, final) = collectLambdas body
|
(params, final) = collectLambdas body
|
||||||
collectLambdas e = ([], e)
|
collectLambdas e = ([], e)
|
||||||
|
|
||||||
collectPis :: Expr -> ([(Text, Expr)], Expr)
|
collectPis :: Expr -> ([(String, Expr)], Expr)
|
||||||
collectPis p@(Pi "" _ _) = ([], p)
|
collectPis p@(Pi "" _ _) = ([], p)
|
||||||
collectPis (Pi x ty body) = ((x, ty) : params, final)
|
collectPis (Pi x ty body) = ((x, ty) : params, final)
|
||||||
where
|
where
|
||||||
(params, final) = collectPis body
|
(params, final) = collectPis body
|
||||||
collectPis e = ([], e)
|
collectPis e = ([], e)
|
||||||
|
|
||||||
groupParams :: [(Text, Expr)] -> [([Text], Expr)]
|
groupParams :: [(String, Expr)] -> [([String], Expr)]
|
||||||
groupParams = foldr addParam []
|
groupParams = foldr addParam []
|
||||||
where
|
where
|
||||||
addParam :: (Text, Expr) -> [([Text], Expr)] -> [([Text], Expr)]
|
addParam :: (String, Expr) -> [([String], Expr)] -> [([String], Expr)]
|
||||||
addParam (x, t) [] = [([x], t)]
|
addParam (x, t) [] = [([x], t)]
|
||||||
addParam (x, t) l@((xs, s) : rest)
|
addParam (x, t) l@((xs, s) : rest)
|
||||||
| incIndices t == s = (x : xs, t) : rest
|
| incIndices t == s = (x : xs, t) : rest
|
||||||
| otherwise = ([x], t) : l
|
| otherwise = ([x], t) : l
|
||||||
|
|
||||||
showParamGroup :: ([Text], Expr) -> Text
|
showParamGroup :: ([String], Expr) -> String
|
||||||
showParamGroup (ids, ty) = parenthesize $ T.unwords ids <> " : " <> pretty ty
|
showParamGroup (ids, ty) = parenthesize $ unwords ids ++ " : " ++ pretty ty
|
||||||
|
|
||||||
helper :: Integer -> Expr -> Text
|
helper :: Integer -> Expr -> String
|
||||||
helper _ (Var _ s) = s
|
helper _ (Var _ 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
|
||||||
where
|
where
|
||||||
res = helper 3 e1 <> " " <> helper 4 e2
|
res = helper 3 e1 ++ " " ++ helper 4 e2
|
||||||
helper k (Pi "" t1 t2) = if k > 2 then parenthesize res else res
|
helper k (Pi "" t1 t2) = if k > 2 then parenthesize res else res
|
||||||
where
|
where
|
||||||
res = helper 3 t1 <> " -> " <> helper 2 t2
|
res = helper 3 t1 ++ " -> " ++ helper 2 t2
|
||||||
helper k e@(Pi{}) = if k > 2 then parenthesize res else res
|
helper k e@(Pi{}) = if k > 2 then parenthesize res else res
|
||||||
where
|
where
|
||||||
(params, body) = collectPis e
|
(params, body) = collectPis e
|
||||||
grouped = showParamGroup <$> groupParams params
|
grouped = showParamGroup <$> groupParams params
|
||||||
res = "∏ " <> T.unwords grouped <> " . " <> pretty body
|
res = "∏ " ++ unwords grouped ++ " . " ++ pretty body
|
||||||
helper k e@(Abs{}) = if k >= 1 then parenthesize res else res
|
helper k e@(Abs{}) = if k >= 1 then parenthesize res else res
|
||||||
where
|
where
|
||||||
(params, body) = collectLambdas e
|
(params, body) = collectLambdas e
|
||||||
grouped = showParamGroup <$> groupParams params
|
grouped = showParamGroup <$> groupParams params
|
||||||
res = "λ " <> T.unwords grouped <> " . " <> pretty body
|
res = "λ " ++ unwords grouped ++ " . " ++ pretty body
|
||||||
|
|
||||||
pretty :: Expr -> Text
|
pretty :: Expr -> String
|
||||||
pretty = helper 0
|
pretty = helper 0
|
||||||
|
|
||||||
prettyS :: Expr -> String
|
|
||||||
prettyS = T.unpack . pretty
|
|
||||||
|
|
||||||
{- --------------- ACTUAL MATH STUFF ---------------- -}
|
{- --------------- ACTUAL MATH STUFF ---------------- -}
|
||||||
|
|
||||||
isSort :: Expr -> Bool
|
isSort :: Expr -> Bool
|
||||||
|
|
|
||||||
|
|
@ -7,22 +7,20 @@ 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 Data.Text (Text)
|
|
||||||
import qualified Data.Text as T
|
|
||||||
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]
|
type InnerState = [String]
|
||||||
|
|
||||||
data CustomErrors = UnboundVariable Text [Text] deriving (Eq, Ord, Show)
|
data CustomErrors = UnboundVariable String [String] deriving (Eq, Ord, Show)
|
||||||
|
|
||||||
instance ShowErrorComponent CustomErrors where
|
instance ShowErrorComponent CustomErrors where
|
||||||
showErrorComponent (UnboundVariable var bound) =
|
showErrorComponent (UnboundVariable var bound) =
|
||||||
"Unbound variable: " ++ T.unpack var ++ ". Did you mean one of: " ++ T.unpack (T.unwords bound) ++ "?"
|
"Unbound variable: " ++ var ++ ". Did you mean one of: " ++ unwords bound ++ "?"
|
||||||
|
|
||||||
type Parser = ParsecT CustomErrors Text (State InnerState)
|
type Parser = ParsecT CustomErrors String (State InnerState)
|
||||||
|
|
||||||
skipSpace :: Parser ()
|
skipSpace :: Parser ()
|
||||||
skipSpace =
|
skipSpace =
|
||||||
|
|
@ -34,11 +32,11 @@ skipSpace =
|
||||||
lexeme :: Parser a -> Parser a
|
lexeme :: Parser a -> Parser a
|
||||||
lexeme = L.lexeme skipSpace
|
lexeme = L.lexeme skipSpace
|
||||||
|
|
||||||
pIdentifier :: Parser Text
|
pIdentifier :: Parser String
|
||||||
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 $ firstChar : rest
|
||||||
|
|
||||||
pVar :: Parser Expr
|
pVar :: Parser Expr
|
||||||
pVar = label "variable" $ lexeme $ do
|
pVar = label "variable" $ lexeme $ do
|
||||||
|
|
@ -48,10 +46,12 @@ pVar = label "variable" $ lexeme $ do
|
||||||
Just i -> return $ Var (fromIntegral i) var
|
Just i -> return $ Var (fromIntegral i) var
|
||||||
Nothing -> customFailure $ UnboundVariable var binders
|
Nothing -> customFailure $ UnboundVariable var binders
|
||||||
|
|
||||||
defChoice :: NE.NonEmpty Text -> Parser ()
|
defChoice :: NE.NonEmpty String -> Parser ()
|
||||||
defChoice options = lexeme $ label (T.unpack $ NE.head options) $ void $ choice $ NE.map chunk options
|
defChoice options = lexeme $ label labelText $ void $ choice $ NE.map string options
|
||||||
|
where
|
||||||
|
labelText = NE.head options
|
||||||
|
|
||||||
pParamGroup :: Parser [(Text, Expr)]
|
pParamGroup :: Parser [(String, Expr)]
|
||||||
pParamGroup = lexeme $ label "parameter group" $ between (char '(') (char ')') $ do
|
pParamGroup = lexeme $ label "parameter group" $ between (char '(') (char ')') $ do
|
||||||
idents <- some pIdentifier
|
idents <- some pIdentifier
|
||||||
_ <- defChoice $ ":" :| []
|
_ <- defChoice $ ":" :| []
|
||||||
|
|
@ -59,7 +59,7 @@ pParamGroup = lexeme $ label "parameter group" $ between (char '(') (char ')') $
|
||||||
modify (flip (foldl $ flip (:)) idents)
|
modify (flip (foldl $ flip (:)) idents)
|
||||||
pure $ zip idents (iterate incIndices ty)
|
pure $ zip idents (iterate incIndices ty)
|
||||||
|
|
||||||
pParams :: Parser [(Text, Expr)]
|
pParams :: Parser [(String, Expr)]
|
||||||
pParams = concat <$> some pParamGroup
|
pParams = concat <$> some pParamGroup
|
||||||
|
|
||||||
pLAbs :: Parser Expr
|
pLAbs :: Parser Expr
|
||||||
|
|
@ -112,5 +112,5 @@ pAppTerm = lexeme $ pLAbs <|> pPAbs <|> pApp
|
||||||
pExpr :: Parser Expr
|
pExpr :: Parser Expr
|
||||||
pExpr = lexeme $ try pArrow <|> pAppTerm
|
pExpr = lexeme $ try pArrow <|> pAppTerm
|
||||||
|
|
||||||
pAll :: Text -> Either Text Expr
|
pAll :: String -> Either String Expr
|
||||||
pAll input = first (T.pack . errorBundlePretty) $ fst $ runIdentity $ runStateT (runParserT pExpr "" input) []
|
pAll input = first errorBundlePretty $ fst $ runIdentity $ runStateT (runParserT pExpr "" input) []
|
||||||
|
|
|
||||||
|
|
@ -1,75 +1 @@
|
||||||
module CheckTests (tests) where
|
module CheckTests where
|
||||||
|
|
||||||
import Check
|
|
||||||
import Expr (Expr (..))
|
|
||||||
import Test.HUnit
|
|
||||||
|
|
||||||
sort :: Test
|
|
||||||
sort = TestCase $ assertEqual "*" (Right Square) (findType [] Star)
|
|
||||||
|
|
||||||
stlc :: Test
|
|
||||||
stlc =
|
|
||||||
TestCase $
|
|
||||||
assertEqual
|
|
||||||
"fun (x : A) (y : B) . x"
|
|
||||||
(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")))
|
|
||||||
|
|
||||||
polyIdent :: Test
|
|
||||||
polyIdent =
|
|
||||||
TestCase $
|
|
||||||
assertEqual
|
|
||||||
"fun (A : *) (x : A) . x"
|
|
||||||
(Right $ Pi "A" Star (Pi "" (Var 0 "A") (Var 1 "A")))
|
|
||||||
(findType [] (Abs "A" Star (Abs "x" (Var 0 "A") (Var 0 "x"))))
|
|
||||||
|
|
||||||
typeCons :: Test
|
|
||||||
typeCons =
|
|
||||||
TestCase $
|
|
||||||
assertEqual
|
|
||||||
"fun (A B : *) . A -> B"
|
|
||||||
(Right $ Pi "" Star (Pi "" Star Star))
|
|
||||||
(findType [] (Abs "A" Star (Abs "B" Star (Pi "" (Var 1 "A") (Var 1 "B")))))
|
|
||||||
|
|
||||||
useTypeCons :: Test
|
|
||||||
useTypeCons =
|
|
||||||
TestCase $
|
|
||||||
assertEqual
|
|
||||||
"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")))))
|
|
||||||
(findType [] $ Abs "C" (Pi "" Star Star) (Abs "A" Star (Abs "x" (App (Var 1 "C") (Var 0 "A")) (Var 0 "x"))))
|
|
||||||
|
|
||||||
dependent :: Test
|
|
||||||
dependent =
|
|
||||||
TestCase $
|
|
||||||
assertEqual
|
|
||||||
"fun (S : *) (x : S) . S -> S"
|
|
||||||
(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"))))
|
|
||||||
|
|
||||||
useDependent :: Test
|
|
||||||
useDependent =
|
|
||||||
TestCase $
|
|
||||||
assertEqual
|
|
||||||
"fun (S : *) (P : S -> *) (x : S) . P x"
|
|
||||||
(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")))))
|
|
||||||
|
|
||||||
big :: Test
|
|
||||||
big =
|
|
||||||
TestCase $
|
|
||||||
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)"
|
|
||||||
(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")))))))))
|
|
||||||
|
|
||||||
tests :: Test
|
|
||||||
tests =
|
|
||||||
TestList
|
|
||||||
[ TestLabel "sort" sort
|
|
||||||
, TestLabel "λ→" stlc
|
|
||||||
, TestLabel "λ2" polyIdent
|
|
||||||
, TestLabel "λω" (TestList [typeCons, useTypeCons])
|
|
||||||
, TestLabel "λP2" (TestList [dependent, useDependent])
|
|
||||||
, TestLabel "λC" big
|
|
||||||
]
|
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -1,18 +1,13 @@
|
||||||
module Main where
|
module Main where
|
||||||
|
|
||||||
import qualified CheckTests as C
|
|
||||||
import qualified ExprTests as E
|
import qualified ExprTests as E
|
||||||
import qualified ParserTests as P
|
import qualified ParserTests as P
|
||||||
import qualified System.Exit as Exit
|
import qualified System.Exit as Exit
|
||||||
import Test.HUnit
|
import Test.HUnit
|
||||||
|
|
||||||
tests :: Test
|
tests :: Test
|
||||||
tests =
|
tests = TestList [ TestLabel "ExprTests" E.tests
|
||||||
TestList
|
, TestLabel "ParserTests" P.tests]
|
||||||
[ TestLabel "ExprTests" E.tests
|
|
||||||
, TestLabel "ParserTests" P.tests
|
|
||||||
, TestLabel "CheckTests" C.tests
|
|
||||||
]
|
|
||||||
|
|
||||||
main :: IO ()
|
main :: IO ()
|
||||||
main = do
|
main = do
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue