From b381c4424ab86b1ba3f8c9b40356565e10b78bf0 Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Fri, 6 Feb 2015 21:56:17 +0100
Subject: [PATCH 01/18] Add bindings for failed definitions (fix #98)
Untested. This is a close variant to Tillmann's proposal in #98.
---
src-lib/PTS/Process/File.hs | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src-lib/PTS/Process/File.hs b/src-lib/PTS/Process/File.hs
index 3402308..b204069 100644
--- a/src-lib/PTS/Process/File.hs
+++ b/src-lib/PTS/Process/File.hs
@@ -168,16 +168,16 @@ processStmt (Bind n args typeAnnot body) = recover () $ do
whenOption optShowFullTerms $ output (nest 2 (sep [text "full type", nest 2 (pretty 0 t' )]))
-- typecheck type
- qq <-
+ (qq, s) <-
flip runEnvironmentT env $
do
qq <- typecheckPull t'
- checkProperType qq (text "in top-level binding of " <+> pretty 0 n) (text "")
- return qq
+ s <- checkProperType qq (text "in top-level binding of " <+> pretty 0 n) (text "")
+ return (qq, s)
-- use declared type to typecheck push
qq <- liftEval (eval qq)
- t <- runEnvironmentT (typecheckPush t qq) env
+ t <- recover (mkVar n qq (Just s)) $ runEnvironmentT (typecheckPush t qq) env
return t
Nothing -> do
-- typecheck pull
From b580313410e57ac45de1cda116181372b64b0821 Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Fri, 6 Feb 2015 23:25:46 +0100
Subject: [PATCH 02/18] Add `recoverWith` method suggested by Tillmann (#98)
Tillmann suggested writing `recover` in terms of `recoverWith`, but that
requires changing more code, and it was not fully obvious to me how to do those
changes.
---
src-lib/Control/Monad/Errors/Class.hs | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/src-lib/Control/Monad/Errors/Class.hs b/src-lib/Control/Monad/Errors/Class.hs
index 23ec66e..16ed888 100644
--- a/src-lib/Control/Monad/Errors/Class.hs
+++ b/src-lib/Control/Monad/Errors/Class.hs
@@ -26,3 +26,7 @@ instance (Monoid e, Error e, MonadErrors e m) => MonadErrors e (StateT s m) wher
instance (Monoid w, MonadErrors e m) => MonadErrors e (WriterT w m) where
recover x = mapWriterT (recover (x, mempty))
annotate f = mapWriterT (annotate f)
+
+recoverWith :: (MonadErrors e m, Functor m) => m b -> m b -> m b
+recoverWith computeFallback action =
+ recover Nothing (fmap Just action) >>= maybe computeFallback return
From d7f52dfcd7b8282b2eb6c7c1622c730a7771b0da Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Sat, 7 Feb 2015 00:23:20 +0100
Subject: [PATCH 03/18] Failing terms: Generate values, not terms (#98)
Follow more closely Tillmann's pseudocode. Instead of generating a typed
variable by hand (duplicating typechecker logic/using a not fully
documented API), and then get from it a value (by evaluation), a type
and a sort, just generate an untyped value by hand (which is easier),
and pass the expected type/sort separately.
I'll admit these conditionals in the needed code are slightly more
complex, but I guess they're OK.
Also, the variable names in the new code are not single letters, which
is somewhat inconsistent (but then, I don't get the old names anyway).
---
src-lib/PTS/Process/File.hs | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/src-lib/PTS/Process/File.hs b/src-lib/PTS/Process/File.hs
index b204069..540a869 100644
--- a/src-lib/PTS/Process/File.hs
+++ b/src-lib/PTS/Process/File.hs
@@ -160,7 +160,7 @@ processStmt (Bind n args typeAnnot body) = recover () $ do
env <- getBindings
- t <- case typeAnnot of
+ (maybeT, tType, tSort) <- case typeAnnot of
Just body' -> do
-- preprocess type
let t' = foldTelescope mkPi args body'
@@ -177,18 +177,21 @@ processStmt (Bind n args typeAnnot body) = recover () $ do
-- use declared type to typecheck push
qq <- liftEval (eval qq)
- t <- recover (mkVar n qq (Just s)) $ runEnvironmentT (typecheckPush t qq) env
- return t
+ t <- recover Nothing $ runEnvironmentT (Just <$> typecheckPush t qq) env
+ return (t, qq, Just s)
Nothing -> do
-- typecheck pull
t <- runEnvironmentT (typecheckPull t) env
q <- liftEval (reify (typeOf t))
output (nest 2 (sep [text "type:", nest 2 (pretty 0 q)]))
- return t
+ return (Just t, typeOf t, sortOf t)
-- do binding
- let v = evalTerm env t
- putBindings ((n, Binding False v (typeOf t) (sortOf t)) : env)
+ let v =
+ case maybeT of
+ Just t -> evalTerm env t
+ Nothing -> ResidualVar n
+ putBindings ((n, Binding False v tType tSort) : env)
processStmt (Assertion t q' t') = recover () $ assert (showAssertion t q' t') $ do
output (text "")
From 9f8363ac8017dfdcf8ede065fb7f45368bed280f Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Sat, 7 Feb 2015 00:28:31 +0100
Subject: [PATCH 04/18] Use checkProperType also without type annotations (fix
#131)
Declarations without type annotations are going to be well-sorted
in *some* PTS, which might be bigger than the one considered. Hence call
checkProperType there anyway. This finally achieves the consistency
discussed in #98.
---
examples/Arithmetics.lpts | 4 ----
src-lib/PTS/Process/File.hs | 5 +++++
2 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/examples/Arithmetics.lpts b/examples/Arithmetics.lpts
index 1e864b8..5fa8dc1 100644
--- a/examples/Arithmetics.lpts
+++ b/examples/Arithmetics.lpts
@@ -7,10 +7,6 @@ There is a built-in type `Int`. In bigger languages than STLC, we can even write
< assert Int : *;
-and even in STLC we can write
-
-> IntSynonym = Int;
-
Values of type `Int` can be written as numeric literals.
> assert 0 : Int;
diff --git a/src-lib/PTS/Process/File.hs b/src-lib/PTS/Process/File.hs
index 540a869..da06843 100644
--- a/src-lib/PTS/Process/File.hs
+++ b/src-lib/PTS/Process/File.hs
@@ -183,6 +183,11 @@ processStmt (Bind n args typeAnnot body) = recover () $ do
-- typecheck pull
t <- runEnvironmentT (typecheckPull t) env
q <- liftEval (reify (typeOf t))
+ flip runEnvironmentT env $
+ do
+ tt <- typecheckPull q
+ checkProperType tt (text "in top-level binding of " <+> pretty 0 n) (text "")
+
output (nest 2 (sep [text "type:", nest 2 (pretty 0 q)]))
return (Just t, typeOf t, sortOf t)
From 7afba16a8d20a13729b321fa5527f26c3a8fe137 Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Sat, 7 Feb 2015 00:51:20 +0100
Subject: [PATCH 05/18] Refactor new code
---
src-lib/PTS/Process/File.hs | 23 ++++++++++-------------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/src-lib/PTS/Process/File.hs b/src-lib/PTS/Process/File.hs
index da06843..da311d6 100644
--- a/src-lib/PTS/Process/File.hs
+++ b/src-lib/PTS/Process/File.hs
@@ -159,6 +159,11 @@ processStmt (Bind n args typeAnnot body) = recover () $ do
whenOption optShowFullTerms $ output (nest 2 (sep [text "full term", nest 2 (pretty 0 t)]))
env <- getBindings
+ let checkTopLevel typ =
+ flip runEnvironmentT env $ do
+ typ <- typecheckPull typ
+ s <- checkProperType typ (text "in top-level binding of " <+> pretty 0 n) (text "")
+ return (typ, s)
(maybeT, tType, tSort) <- case typeAnnot of
Just body' -> do
@@ -168,35 +173,27 @@ processStmt (Bind n args typeAnnot body) = recover () $ do
whenOption optShowFullTerms $ output (nest 2 (sep [text "full type", nest 2 (pretty 0 t' )]))
-- typecheck type
- (qq, s) <-
- flip runEnvironmentT env $
- do
- qq <- typecheckPull t'
- s <- checkProperType qq (text "in top-level binding of " <+> pretty 0 n) (text "")
- return (qq, s)
+ (qq, s) <- checkTopLevel t'
-- use declared type to typecheck push
qq <- liftEval (eval qq)
t <- recover Nothing $ runEnvironmentT (Just <$> typecheckPush t qq) env
- return (t, qq, Just s)
+ return (t, qq, s)
Nothing -> do
-- typecheck pull
t <- runEnvironmentT (typecheckPull t) env
q <- liftEval (reify (typeOf t))
- flip runEnvironmentT env $
- do
- tt <- typecheckPull q
- checkProperType tt (text "in top-level binding of " <+> pretty 0 n) (text "")
+ (_, s) <- checkTopLevel q
output (nest 2 (sep [text "type:", nest 2 (pretty 0 q)]))
- return (Just t, typeOf t, sortOf t)
+ return (Just t, typeOf t, s)
-- do binding
let v =
case maybeT of
Just t -> evalTerm env t
Nothing -> ResidualVar n
- putBindings ((n, Binding False v tType tSort) : env)
+ putBindings ((n, Binding False v tType (Just tSort)) : env)
processStmt (Assertion t q' t') = recover () $ assert (showAssertion t q' t') $ do
output (text "")
From a26ad41b4a08f46e1aecbb924f030323a41ce3b4 Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Sat, 7 Feb 2015 01:35:17 +0100
Subject: [PATCH 06/18] Share code in prettyprinter
---
src-lib/PTS/Syntax/Pretty.hs | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/src-lib/PTS/Syntax/Pretty.hs b/src-lib/PTS/Syntax/Pretty.hs
index 39ed1df..c651f29 100644
--- a/src-lib/PTS/Syntax/Pretty.hs
+++ b/src-lib/PTS/Syntax/Pretty.hs
@@ -163,8 +163,10 @@ prettyArgs args = sep (map f args) where
f (ns, q) = hsep [pretty 0 n | n <- ns] <+> text ":" <+> pretty 0 q
instance Pretty Stmt where
- pretty p (Bind n args Nothing t) = pretty 0 n <+> prettyArgs args <+> text "=" <+> pretty 0 t
- pretty p (Bind n args (Just t') t) = pretty 0 n <+> prettyArgs args <+> text ":" <+> pretty 0 t' <+> text "=" <+> pretty 0 t
+ pretty p (Bind n args t' t) =
+ pretty 0 n <+> prettyArgs args <+>
+ maybe empty (\t' -> text ":" <+> pretty 0 t') t' <+>
+ text "=" <+> pretty 0 t
pretty p (Term t) = pretty 0 t
pretty p (Assertion t q' t') = text "assert" <+> prettyAssertion t q' t'
pretty p (Import n) = text "import" <+> pretty 0 n
From f22fed79b0f85ad6c68a15d7000ddea87f76ac47 Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Sat, 7 Feb 2015 00:57:44 +0100
Subject: [PATCH 07/18] Prototype postulates (#95)
This is just (the semantics of) Proposal 1 (with a twist), based on the
code for Bind.
No test added yet.
---
src-lib/PTS/Process/File.hs | 11 +++++++++++
src-lib/PTS/Syntax/Statement.hs | 1 +
2 files changed, 12 insertions(+)
diff --git a/src-lib/PTS/Process/File.hs b/src-lib/PTS/Process/File.hs
index da311d6..5b7fc1b 100644
--- a/src-lib/PTS/Process/File.hs
+++ b/src-lib/PTS/Process/File.hs
@@ -195,6 +195,17 @@ processStmt (Bind n args typeAnnot body) = recover () $ do
Nothing -> ResidualVar n
putBindings ((n, Binding False v tType (Just tSort)) : env)
+processStmt (Postulate n typ) = recover () $ do
+ -- XXX Looks like a variant of Bind, maybe it should be?
+ env <- getBindings
+ (typ, s) <- flip runEnvironmentT env $ do
+ typ <- typecheckPull typ
+ s <- checkProperType typ (text "in top-level binding of " <+> pretty 0 n) (text "")
+ typ <- liftEval (eval typ)
+ return (typ, s)
+ let v = ResidualVar n
+ putBindings ((n, Binding False v typ (Just s)) : env)
+
processStmt (Assertion t q' t') = recover () $ assert (showAssertion t q' t') $ do
output (text "")
output (text "process assertion")
diff --git a/src-lib/PTS/Syntax/Statement.hs b/src-lib/PTS/Syntax/Statement.hs
index b847be8..8b590e1 100644
--- a/src-lib/PTS/Syntax/Statement.hs
+++ b/src-lib/PTS/Syntax/Statement.hs
@@ -14,3 +14,4 @@ data Stmt
| Import ModuleName
| StmtPos Position Stmt
| Assertion Term (Maybe Term) (Maybe Term)
+ | Postulate Name Term
From 5d34f40ade5021001cbfa3304654a11be76055a0 Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Sat, 7 Feb 2015 01:38:10 +0100
Subject: [PATCH 08/18] Turn Postulates into bodyless Binding (#95)
---
src-lib/PTS/Process/File.hs | 43 +++++++++++++++------------------
src-lib/PTS/Syntax/Parser.hs | 2 +-
src-lib/PTS/Syntax/Pretty.hs | 2 +-
src-lib/PTS/Syntax/Statement.hs | 3 +--
4 files changed, 23 insertions(+), 27 deletions(-)
diff --git a/src-lib/PTS/Process/File.hs b/src-lib/PTS/Process/File.hs
index 5b7fc1b..2f6c9c0 100644
--- a/src-lib/PTS/Process/File.hs
+++ b/src-lib/PTS/Process/File.hs
@@ -13,6 +13,7 @@ import Control.Monad.State (MonadState, get, put, evalStateT)
import Control.Monad.Trans (MonadIO (liftIO))
import Control.Monad.Log (MonadLog, runConsoleLogT)
+import Data.Traversable (traverse)
import Data.Maybe (fromMaybe)
import Data.Monoid (mempty)
import qualified Data.Map as Map
@@ -121,7 +122,7 @@ liftEval action = do
env <- getBindings
return (runEval env action)
-processFile :: (Functor m, MonadErrors [PTSError] m, MonadReader Options m, MonadState ProcessingState m, MonadIO m, MonadLog m, MonadAssertions m) => FilePath -> m (Maybe (Module Eval))
+processFile :: (Functor m, MonadErrors [PTSError] m, MonadReader Options m, MonadState ProcessingState m, MonadIO m, MonadLog m, MonadAssertions m, Applicative m) => FilePath -> m (Maybe (Module Eval))
processFile file = do
(maybeName, rest) <- processFileInt file
return $ filterRet <$> maybeName <*> pure rest
@@ -149,14 +150,17 @@ processStmt (Term t) = recover () $ do
output (nest 2 (sep [text "value:", nest 2 (pretty 0 x)]))
processStmt (Bind n args typeAnnot body) = recover () $ do
- let t = foldTelescope mkLam args body
+ let t = foldTelescope mkLam args <$> body
pts <- getLanguage
output (text "")
output (text "process binding of" <+> pretty 0 n)
-- preprocess body
- output (nest 2 (sep [text "original term:", nest 2 (pretty 0 t)]))
- whenOption optShowFullTerms $ output (nest 2 (sep [text "full term", nest 2 (pretty 0 t)]))
+ flip traverse t $
+ \t ->
+ do
+ output (nest 2 (sep [text "original term:", nest 2 (pretty 0 t)]))
+ whenOption optShowFullTerms $ output (nest 2 (sep [text "full term", nest 2 (pretty 0 t)]))
env <- getBindings
let checkTopLevel typ =
@@ -170,23 +174,27 @@ processStmt (Bind n args typeAnnot body) = recover () $ do
-- preprocess type
let t' = foldTelescope mkPi args body'
output (nest 2 (sep [text "specified type:", nest 2 (pretty 0 t')]))
- whenOption optShowFullTerms $ output (nest 2 (sep [text "full type", nest 2 (pretty 0 t' )]))
+ whenOption optShowFullTerms $ output (nest 2 (sep [text "full type", nest 2 (pretty 0 t')]))
-- typecheck type
(qq, s) <- checkTopLevel t'
-- use declared type to typecheck push
qq <- liftEval (eval qq)
- t <- recover Nothing $ runEnvironmentT (Just <$> typecheckPush t qq) env
+ t <- recover Nothing $ runEnvironmentT (traverse (flip typecheckPush qq) t) env
return (t, qq, s)
Nothing -> do
-- typecheck pull
- t <- runEnvironmentT (typecheckPull t) env
- q <- liftEval (reify (typeOf t))
- (_, s) <- checkTopLevel q
-
- output (nest 2 (sep [text "type:", nest 2 (pretty 0 q)]))
- return (Just t, typeOf t, s)
+ case t of
+ Just t -> do
+ t <- runEnvironmentT (typecheckPull t) env
+ q <- liftEval (reify (typeOf t))
+ (_, s) <- checkTopLevel q
+
+ output (nest 2 (sep [text "type:", nest 2 (pretty 0 q)]))
+ return (Just t, typeOf t, s)
+ Nothing ->
+ prettyFail $ text "Binding for " <+> pretty 0 n <+> text "specifies neither type nor body."
-- do binding
let v =
@@ -195,17 +203,6 @@ processStmt (Bind n args typeAnnot body) = recover () $ do
Nothing -> ResidualVar n
putBindings ((n, Binding False v tType (Just tSort)) : env)
-processStmt (Postulate n typ) = recover () $ do
- -- XXX Looks like a variant of Bind, maybe it should be?
- env <- getBindings
- (typ, s) <- flip runEnvironmentT env $ do
- typ <- typecheckPull typ
- s <- checkProperType typ (text "in top-level binding of " <+> pretty 0 n) (text "")
- typ <- liftEval (eval typ)
- return (typ, s)
- let v = ResidualVar n
- putBindings ((n, Binding False v typ (Just s)) : env)
-
processStmt (Assertion t q' t') = recover () $ assert (showAssertion t q' t') $ do
output (text "")
output (text "process assertion")
diff --git a/src-lib/PTS/Syntax/Parser.hs b/src-lib/PTS/Syntax/Parser.hs
index 4c2555c..462aa78 100644
--- a/src-lib/PTS/Syntax/Parser.hs
+++ b/src-lib/PTS/Syntax/Parser.hs
@@ -113,7 +113,7 @@ stmt = withPos StmtPos $ asum
, Import <$> (keyword "import" *> modname <* semi)
, Assertion <$> (keyword "assert" *> expr) <*> optionMaybe (colon1 *> expr) <*> optionMaybe (assign *> expr) <* semi
, try (Term <$> expr <* semi)
- , Bind <$> ident <*> telescope <*> optionMaybe (colon1 *> expr) <* assign <*> expr <* semi]
+ , Bind <$> ident <*> telescope <*> optionMaybe (colon1 *> expr) <* assign <*> (Just <$> expr) <* semi]
stmts = many (optional pragma *> stmt)
diff --git a/src-lib/PTS/Syntax/Pretty.hs b/src-lib/PTS/Syntax/Pretty.hs
index c651f29..04f3b2e 100644
--- a/src-lib/PTS/Syntax/Pretty.hs
+++ b/src-lib/PTS/Syntax/Pretty.hs
@@ -166,7 +166,7 @@ instance Pretty Stmt where
pretty p (Bind n args t' t) =
pretty 0 n <+> prettyArgs args <+>
maybe empty (\t' -> text ":" <+> pretty 0 t') t' <+>
- text "=" <+> pretty 0 t
+ maybe empty (\t -> text "=" <+> pretty 0 t) t
pretty p (Term t) = pretty 0 t
pretty p (Assertion t q' t') = text "assert" <+> prettyAssertion t q' t'
pretty p (Import n) = text "import" <+> pretty 0 n
diff --git a/src-lib/PTS/Syntax/Statement.hs b/src-lib/PTS/Syntax/Statement.hs
index 8b590e1..ff8d872 100644
--- a/src-lib/PTS/Syntax/Statement.hs
+++ b/src-lib/PTS/Syntax/Statement.hs
@@ -8,10 +8,9 @@ import PTS.Syntax.Telescope (Telescope)
import PTS.Syntax.Term (Term)
data Stmt
- = Bind Name (Telescope Term) (Maybe Term) Term
+ = Bind Name (Telescope Term) (Maybe Term) (Maybe Term)
| Term Term
| Export Name
| Import ModuleName
| StmtPos Position Stmt
| Assertion Term (Maybe Term) (Maybe Term)
- | Postulate Name Term
From 3d98ef51b6d719256c9cff85bab6aac4e19dcac0 Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Sat, 7 Feb 2015 01:50:54 +0100
Subject: [PATCH 09/18] Add parsing for postulates (fix #95)
---
src-lib/PTS/Syntax/Parser.hs | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src-lib/PTS/Syntax/Parser.hs b/src-lib/PTS/Syntax/Parser.hs
index 462aa78..226724d 100644
--- a/src-lib/PTS/Syntax/Parser.hs
+++ b/src-lib/PTS/Syntax/Parser.hs
@@ -112,6 +112,8 @@ stmt = withPos StmtPos $ asum
[ Export <$> (keyword "export" *> ident <* semi)
, Import <$> (keyword "import" *> modname <* semi)
, Assertion <$> (keyword "assert" *> expr) <*> optionMaybe (colon1 *> expr) <*> optionMaybe (assign *> expr) <* semi
+ -- we don't support argument telescopes for postulates -- yet!
+ , Bind <$> (keyword "postulate" *> ident) <*> pure [] <*> (colon1 *> (Just <$> expr)) <*> pure Nothing <* semi
, try (Term <$> expr <* semi)
, Bind <$> ident <*> telescope <*> optionMaybe (colon1 *> expr) <* assign <*> (Just <$> expr) <* semi]
@@ -168,7 +170,7 @@ pragma = lexem $ do
-- LEXER --
---------
-keywords = ["Lambda", "lambda", "Pi", "if0", "then", "else", "->", "add", "mul", "sub", "div", "module", "import", "export", "assert", "language", "_("]
+keywords = ["Lambda", "lambda", "Pi", "if0", "then", "else", "->", "add", "mul", "sub", "div", "module", "import", "export", "assert", "language", "postulate", "_("]
identChar x = not (isSpace x) && x `notElem` ".:=;/()[]$"
From 60664e915769e0d08adf947fd0bbeab8cd1b624b Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Sun, 8 Feb 2015 19:58:25 +0100
Subject: [PATCH 10/18] Support telescopes for postulates
That's convenient when refactoring a binding to a postulate, and since
postulates reuse code for bindings, it's also trivial to support.
For instance, now we can turn:
> cons1 (A B : *) : A -> B -> Pair1 A B = ...;
into:
> postulate cons1 (A B : *) : A -> B -> Pair1 A B;
---
src-lib/PTS/Syntax/Parser.hs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src-lib/PTS/Syntax/Parser.hs b/src-lib/PTS/Syntax/Parser.hs
index 226724d..43968d5 100644
--- a/src-lib/PTS/Syntax/Parser.hs
+++ b/src-lib/PTS/Syntax/Parser.hs
@@ -113,7 +113,7 @@ stmt = withPos StmtPos $ asum
, Import <$> (keyword "import" *> modname <* semi)
, Assertion <$> (keyword "assert" *> expr) <*> optionMaybe (colon1 *> expr) <*> optionMaybe (assign *> expr) <* semi
-- we don't support argument telescopes for postulates -- yet!
- , Bind <$> (keyword "postulate" *> ident) <*> pure [] <*> (colon1 *> (Just <$> expr)) <*> pure Nothing <* semi
+ , Bind <$> (keyword "postulate" *> ident) <*> telescope <*> (colon1 *> (Just <$> expr)) <*> pure Nothing <* semi
, try (Term <$> expr <* semi)
, Bind <$> ident <*> telescope <*> optionMaybe (colon1 *> expr) <* assign <*> (Just <$> expr) <* semi]
From 59a0613f5ace1ce56eb4c9c555ddafa989334cd7 Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Sun, 8 Feb 2015 20:12:16 +0100
Subject: [PATCH 11/18] Add example/testcase/doc for postulates
---
examples/Pair1WithPostulates.lpts | 44 +++++++++++++++++++++++++++++++
pts.cabal | 1 +
src-test/tests.hs | 1 +
3 files changed, 46 insertions(+)
create mode 100644 examples/Pair1WithPostulates.lpts
diff --git a/examples/Pair1WithPostulates.lpts b/examples/Pair1WithPostulates.lpts
new file mode 100644
index 0000000..19d9cdb
--- /dev/null
+++ b/examples/Pair1WithPostulates.lpts
@@ -0,0 +1,44 @@
+> language fomega;
+> module Data.Pair1;
+
+Pairs on the expression level. Requires at least System F. Since Pair is an
+in-language type constructor, not a macro, we actually require Fomega.
+
+> Pair1 (A B : *) : * = Pi R : * . (A -> B -> R) -> R;
+
+To test postulates, here we postulate cons1:
+
+> postulate cons1 (A B : *) : A -> B -> Pair1 A B;
+
+even though it's easy to define it:
+
+> cons1impl (A B : *) : A -> B -> Pair1 A B = lambda a b R k . k a b;
+
+Notice how postulates admit telescopes -- we don't have to desugar them by hand:
+
+> postulate cons1 : Pi (A B : *). A -> B -> Pair1 A B;
+> assert cons1 : Pi (A B : *) . A -> B -> Pair1 A B;
+
+> fst1 (A B : *) : Pair1 A B -> A = lambda p . p A (lambda a b . a);
+> snd1 (A B : *) : Pair1 A B -> B = lambda p . p B (lambda a b . b);
+>
+> pair1 (A B C D : *) : (A -> B) -> (C -> D) -> (Pair1 A C -> Pair1 B D) =
+> lambda f g p . cons1 B D (f (fst1 A C p)) (g (snd1 A C p));
+>
+> both1 (A B C : *) : (A -> B) -> (A -> C) -> (A -> Pair1 B C) =
+> lambda f g a . cons1 B C (f a) (g a);
+>
+> curry1 (A B C : *) : (Pair1 A B -> C) -> (A -> B -> C) =
+> lambda f a b . f (cons1 A B a b);
+>
+> uncurry1 (A B C : *) : (A -> B -> C) -> (Pair1 A B -> C) =
+> lambda f p . f (fst1 A B p) (snd1 A B p);
+>
+> export Pair1;
+> export cons1;
+> export fst1;
+> export snd1;
+> export pair1;
+> export both1;
+> export curry1;
+> export uncurry1;
diff --git a/pts.cabal b/pts.cabal
index d66fe8a..0ddd1a5 100644
--- a/pts.cabal
+++ b/pts.cabal
@@ -14,6 +14,7 @@ Extra-source-files: examples/Arithmetics.lpts
examples/Functions.lpts
examples/Inference.lpts
examples/Syntax.lpts
+ examples/Pair1WithPostulates.lpts
Data-files: emacs/pts-mode.el
Cabal-version: >= 1.8
diff --git a/src-test/tests.hs b/src-test/tests.hs
index 38bbf72..a568166 100644
--- a/src-test/tests.hs
+++ b/src-test/tests.hs
@@ -21,5 +21,6 @@ tests =
, testFile True ["examples"] "ChurchNumbers.lpts"
, testFile True ["examples"] "Functions.lpts"
, testFile True ["examples"] "Inference.lpts"
+ , testFile True ["examples"] "Pair1WithPostulates.lpts"
, testFile True ["examples"] "Syntax.lpts"
]
From f729dc818c089c31e41dfb5fce8814c73f7c24d6 Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Sun, 8 Feb 2015 21:59:42 +0100
Subject: [PATCH 12/18] Support cabal repl tests
Add filepath explicitly for the tests as well (even though elsewhere
it's implied by the pts library).
---
pts.cabal | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/pts.cabal b/pts.cabal
index 0ddd1a5..fdcd242 100644
--- a/pts.cabal
+++ b/pts.cabal
@@ -141,5 +141,6 @@ Test-suite tests
HUnit,
parsec == 3.1.*,
pts,
- directory >= 1.2.0.1 && < 1.3
+ directory >= 1.2.0.1 && < 1.3,
+ filepath
-- Ghc-options: -Wall -fno-warn-orphans
From c5bd99c9cafe76a7238c8b1e1acab29ad8a4a908 Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Sun, 8 Feb 2015 22:12:48 +0100
Subject: [PATCH 13/18] Add assertion to Syntax.lpts
Files are shown in testing output only if they contain assertions (which
seems unfortunate), so add some now.
---
examples/Syntax.lpts | 1 +
1 file changed, 1 insertion(+)
diff --git a/examples/Syntax.lpts b/examples/Syntax.lpts
index 892a4d2..18b718b 100644
--- a/examples/Syntax.lpts
+++ b/examples/Syntax.lpts
@@ -4,3 +4,4 @@
> bar =
> 2;
> baz = 3;
+> assert add bar baz = 5;
From eca9624e8bdb4c89e49cd2bb6fd131372fca706b Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Sun, 8 Feb 2015 22:16:22 +0100
Subject: [PATCH 14/18] Test automatically all files under examples/
---
src-test/PTS/File/Tests.hs | 19 ++++++++++++++++++-
src-test/tests.hs | 22 +++++++++-------------
2 files changed, 27 insertions(+), 14 deletions(-)
diff --git a/src-test/PTS/File/Tests.hs b/src-test/PTS/File/Tests.hs
index 0c159eb..d259ed9 100644
--- a/src-test/PTS/File/Tests.hs
+++ b/src-test/PTS/File/Tests.hs
@@ -1,6 +1,7 @@
module PTS.File.Tests
( testFile
, testFileWithOptions
+ , testDir
) where
import Control.Monad.Assertions (collectAssertions)
@@ -13,7 +14,8 @@ import PTS.Process.File (processFile)
import PTS.Process.Main (runOptMonads, withEmptyState)
import PTS.Options (Options, defaultOptions, optPath, optLiterate, optQuiet)
-import System.Directory (findFile)
+import System.Directory (findFile, getDirectoryContents)
+import System.FilePath (takeExtension)
import Test.Framework (Test, testGroup, buildTest)
import Test.Framework.Providers.HUnit (testCase)
@@ -38,3 +40,18 @@ testFile literate path
{ optQuiet = True
, optLiterate = literate
, optPath = path})
+
+testDir :: FilePath -> IO [Test]
+testDir path = do
+ files <- getDirectoryContents path
+ return $
+ [ testFile literate [path] validFile |
+ file <- files,
+ (validFile, literate) <-
+ case takeExtension file of
+ ".lpts" ->
+ [(file, True)]
+ ".pts" ->
+ [(file, False)]
+ _ -> []
+ ]
diff --git a/src-test/tests.hs b/src-test/tests.hs
index a568166..4e5e91d 100644
--- a/src-test/tests.hs
+++ b/src-test/tests.hs
@@ -9,18 +9,14 @@ import Test.QuickCheck hiding ((.&.))
import PTS.Syntax.Substitution.Tests
import PTS.Syntax.Parser.Tests
import PTS.Syntax.Pretty.Tests
-import PTS.File.Tests (testFile)
+import PTS.File.Tests (testFile, testDir)
-main = defaultMain Main.tests
+main = Main.tests >>= defaultMain
-tests =
- [ PTS.Syntax.Parser.Tests.tests
- , PTS.Syntax.Pretty.Tests.tests
- , PTS.Syntax.Substitution.Tests.tests
- , testFile True ["examples"] "Arithmetics.lpts"
- , testFile True ["examples"] "ChurchNumbers.lpts"
- , testFile True ["examples"] "Functions.lpts"
- , testFile True ["examples"] "Inference.lpts"
- , testFile True ["examples"] "Pair1WithPostulates.lpts"
- , testFile True ["examples"] "Syntax.lpts"
- ]
+tests = do
+ examples <- testDir "examples"
+ return $
+ [ PTS.Syntax.Parser.Tests.tests
+ , PTS.Syntax.Pretty.Tests.tests
+ , PTS.Syntax.Substitution.Tests.tests
+ ] ++ examples
From 41585ddd1b1493e3df9fce3ea2954bca893bc6eb Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Tue, 10 Feb 2015 12:45:18 +0100
Subject: [PATCH 15/18] Coding changes on
5d34f40ade5021001cbfa3304654a11be76055a0
As suggested in
https://github.com/Blaisorblade/pts/commit/5d34f40ade5021001cbfa3304654a11be76055a0
Reindenting/renaming deferred.
---
src-lib/PTS/Process/File.hs | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src-lib/PTS/Process/File.hs b/src-lib/PTS/Process/File.hs
index 2f6c9c0..e20df94 100644
--- a/src-lib/PTS/Process/File.hs
+++ b/src-lib/PTS/Process/File.hs
@@ -122,7 +122,7 @@ liftEval action = do
env <- getBindings
return (runEval env action)
-processFile :: (Functor m, MonadErrors [PTSError] m, MonadReader Options m, MonadState ProcessingState m, MonadIO m, MonadLog m, MonadAssertions m, Applicative m) => FilePath -> m (Maybe (Module Eval))
+processFile :: (Functor m, Applicative m, MonadErrors [PTSError] m, MonadReader Options m, MonadState ProcessingState m, MonadIO m, MonadLog m, MonadAssertions m) => FilePath -> m (Maybe (Module Eval))
processFile file = do
(maybeName, rest) <- processFileInt file
return $ filterRet <$> maybeName <*> pure rest
@@ -156,7 +156,7 @@ processStmt (Bind n args typeAnnot body) = recover () $ do
output (text "process binding of" <+> pretty 0 n)
-- preprocess body
- flip traverse t $
+ for t $
\t ->
do
output (nest 2 (sep [text "original term:", nest 2 (pretty 0 t)]))
From 68e8a04ecbb6fc4c332f3bafdfc49c6073873dec Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Tue, 10 Feb 2015 12:58:14 +0100
Subject: [PATCH 16/18] Reindent/rename (follow up to previous commit)
---
src-lib/PTS/Process/File.hs | 19 +++++++++----------
1 file changed, 9 insertions(+), 10 deletions(-)
diff --git a/src-lib/PTS/Process/File.hs b/src-lib/PTS/Process/File.hs
index e20df94..8225444 100644
--- a/src-lib/PTS/Process/File.hs
+++ b/src-lib/PTS/Process/File.hs
@@ -13,7 +13,7 @@ import Control.Monad.State (MonadState, get, put, evalStateT)
import Control.Monad.Trans (MonadIO (liftIO))
import Control.Monad.Log (MonadLog, runConsoleLogT)
-import Data.Traversable (traverse)
+import Data.Traversable (traverse, for)
import Data.Maybe (fromMaybe)
import Data.Monoid (mempty)
import qualified Data.Map as Map
@@ -150,17 +150,16 @@ processStmt (Term t) = recover () $ do
output (nest 2 (sep [text "value:", nest 2 (pretty 0 x)]))
processStmt (Bind n args typeAnnot body) = recover () $ do
- let t = foldTelescope mkLam args <$> body
+ let maybeT = foldTelescope mkLam args <$> body
pts <- getLanguage
output (text "")
output (text "process binding of" <+> pretty 0 n)
-- preprocess body
- for t $
- \t ->
- do
- output (nest 2 (sep [text "original term:", nest 2 (pretty 0 t)]))
- whenOption optShowFullTerms $ output (nest 2 (sep [text "full term", nest 2 (pretty 0 t)]))
+
+ for maybeT $ \t -> do
+ output (nest 2 (sep [text "original term:", nest 2 (pretty 0 t)]))
+ whenOption optShowFullTerms $ output (nest 2 (sep [text "full term", nest 2 (pretty 0 t)]))
env <- getBindings
let checkTopLevel typ =
@@ -181,11 +180,11 @@ processStmt (Bind n args typeAnnot body) = recover () $ do
-- use declared type to typecheck push
qq <- liftEval (eval qq)
- t <- recover Nothing $ runEnvironmentT (traverse (flip typecheckPush qq) t) env
- return (t, qq, s)
+ maybeT <- recover Nothing $ runEnvironmentT (traverse (flip typecheckPush qq) maybeT) env
+ return (maybeT, qq, s)
Nothing -> do
-- typecheck pull
- case t of
+ case maybeT of
Just t -> do
t <- runEnvironmentT (typecheckPull t) env
q <- liftEval (reify (typeOf t))
From e0506704a15cf011b792f35c8717732d254ff662 Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Tue, 10 Feb 2015 13:30:07 +0100
Subject: [PATCH 17/18] Revise example
In response to
https://github.com/Blaisorblade/pts/commit/59a0613f5ace1ce56eb4c9c555ddafa989334cd7#commitcomment-9673662
---
examples/Pair1WithPostulates.lpts | 7 ++++---
1 file changed, 4 insertions(+), 3 deletions(-)
diff --git a/examples/Pair1WithPostulates.lpts b/examples/Pair1WithPostulates.lpts
index 19d9cdb..25cf65d 100644
--- a/examples/Pair1WithPostulates.lpts
+++ b/examples/Pair1WithPostulates.lpts
@@ -14,10 +14,11 @@ even though it's easy to define it:
> cons1impl (A B : *) : A -> B -> Pair1 A B = lambda a b R k . k a b;
-Notice how postulates admit telescopes -- we don't have to desugar them by hand:
+Notice how postulates admit telescopes, which are desugared to Pi-types:
+
+> assert cons1 : Pi (A B : *) . A -> B -> Pair1 A B;
+
-> postulate cons1 : Pi (A B : *). A -> B -> Pair1 A B;
-> assert cons1 : Pi (A B : *) . A -> B -> Pair1 A B;
> fst1 (A B : *) : Pair1 A B -> A = lambda p . p A (lambda a b . a);
> snd1 (A B : *) : Pair1 A B -> B = lambda p . p B (lambda a b . b);
From 2fa8f0868350a92750585a74e8bff1b4fc508244 Mon Sep 17 00:00:00 2001
From: "Paolo G. Giarrusso"
Date: Tue, 10 Feb 2015 14:16:11 +0100
Subject: [PATCH 18/18] Update keyword list in pts-mode.el
As requested in
https://github.com/Blaisorblade/pts/commit/3d98ef51b6d719256c9cff85bab6aac4e19dcac0
---
emacs/pts-mode.el | 2 +-
src-lib/PTS/Syntax/Parser.hs | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/emacs/pts-mode.el b/emacs/pts-mode.el
index bec82bb..b991f7d 100644
--- a/emacs/pts-mode.el
+++ b/emacs/pts-mode.el
@@ -1,5 +1,5 @@
(defvar pts-keywords
- '("language" "module" "import" "export" "assert"
+ '("language" "module" "import" "export" "postulate" "assert"
"Lambda" "lambda" "Pi" "->"
"if0" "then" "else")
"Keywords of PTS, that is, reserved words with special
diff --git a/src-lib/PTS/Syntax/Parser.hs b/src-lib/PTS/Syntax/Parser.hs
index 43968d5..27351d2 100644
--- a/src-lib/PTS/Syntax/Parser.hs
+++ b/src-lib/PTS/Syntax/Parser.hs
@@ -170,6 +170,7 @@ pragma = lexem $ do
-- LEXER --
---------
+-- When updating, please also update emacs/pts-mode.el.
keywords = ["Lambda", "lambda", "Pi", "if0", "then", "else", "->", "add", "mul", "sub", "div", "module", "import", "export", "assert", "language", "postulate", "_("]
identChar x = not (isSpace x) && x `notElem` ".:=;/()[]$"