Add syntax for pattern types and literals (i.e. sum types)

This commit is contained in:
Gabriel Gonzalez 2016-09-21 20:39:40 -07:00
parent f34b07be49
commit 954e8619b6
3 changed files with 174 additions and 57 deletions

View File

@ -259,10 +259,14 @@ data Expr a
| MaybeLit (Expr a) (Vector (Expr a))
-- | > MaybeFold ~ Maybe/fold
| MaybeFold
-- | > Record [(k1, t1), (k2, t2)] ~ { k1 : t1, k2 : t1 }
-- | > Record [(k1, t1), (k2, t2)] ~ { k1 : t1, k2 : t2 }
| Record (Map Text (Expr a))
-- | > RecordLit [(k1, v1), (k2, v2)] ~ { k1 = v1, k2 = v2 }
| RecordLit (Map Text (Expr a))
-- | > Pattern [(k1, t1), (k2, t2)] ~ < k1 : t1, k2 : t2 >
| Pattern (Map Text (Expr a))
-- | > PatternLit k1 v1 [(k2, v2)] ~ < k1 = v1, k2 : t2 >
| PatternLit Text (Expr a) (Map Text (Expr a))
-- | > Field e x ~ e.x
| Field (Expr a) Text
-- | > Embed path ~ #path
@ -277,62 +281,69 @@ instance Applicative Expr where
instance Monad Expr where
return = pure
Const c >>= _ = Const c
Var v >>= _ = Var v
Lam x _A b >>= k = Lam x (_A >>= k) ( b >>= k)
Pi x _A _B >>= k = Pi x (_A >>= k) (_B >>= k)
App f a >>= k = App (f >>= k) (a >>= k)
Let f as mt r e >>= k = Let f as' (fmap (>>= k) mt) (r >>= k) (e >>= k)
Const c >>= _ = Const c
Var v >>= _ = Var v
Lam x _A b >>= k = Lam x (_A >>= k) ( b >>= k)
Pi x _A _B >>= k = Pi x (_A >>= k) (_B >>= k)
App f a >>= k = App (f >>= k) (a >>= k)
Let f as mt r e >>= k = Let f as' (fmap (>>= k) mt) (r >>= k) (e >>= k)
where
as' = do
(x, t) <- as
return (x, t >>= k)
Annot x t >>= k = Annot (x >>= k) (t >>= k)
Bool >>= _ = Bool
BoolLit b >>= _ = BoolLit b
BoolAnd l r >>= k = BoolAnd (l >>= k) (r >>= k)
BoolOr l r >>= k = BoolOr (l >>= k) (r >>= k)
BoolEQ l r >>= k = BoolEQ (l >>= k) (r >>= k)
BoolNE l r >>= k = BoolNE (l >>= k) (r >>= k)
BoolIf x y z >>= k = BoolIf (x >>= k) (y >>= k) (z >>= k)
Natural >>= _ = Natural
NaturalLit n >>= _ = NaturalLit n
NaturalFold >>= _ = NaturalFold
NaturalIsZero >>= _ = NaturalIsZero
NaturalEven >>= _ = NaturalEven
NaturalOdd >>= _ = NaturalOdd
NaturalPlus l r >>= k = NaturalPlus (l >>= k) (r >>= k)
NaturalTimes l r >>= k = NaturalTimes (l >>= k) (r >>= k)
Integer >>= _ = Integer
IntegerLit n >>= _ = IntegerLit n
Double >>= _ = Double
DoubleLit n >>= _ = DoubleLit n
Text >>= _ = Text
TextLit t >>= _ = TextLit t
TextAppend l r >>= k = TextAppend (l >>= k) (r >>= k)
TextConcat >>= _ = TextConcat
List >>= _ = List
ListLit t es >>= k = ListLit (t >>= k) (fmap (>>= k) es)
ListBuild >>= _ = ListBuild
ListFold >>= _ = ListFold
ListLength >>= _ = ListLength
ListHead >>= _ = ListHead
ListLast >>= _ = ListLast
ListIndexed >>= _ = ListIndexed
ListReverse >>= _ = ListReverse
ListAppend l r >>= k = ListAppend (l >>= k) (r >>= k)
ListConcat >>= _ = ListConcat
Maybe >>= _ = Maybe
MaybeLit t es >>= k = MaybeLit (t >>= k) (fmap (>>= k) es)
MaybeFold >>= _ = MaybeFold
Record kts >>= k = Record (Data.Map.fromAscList kts')
Annot x t >>= k = Annot (x >>= k) (t >>= k)
Bool >>= _ = Bool
BoolLit b >>= _ = BoolLit b
BoolAnd l r >>= k = BoolAnd (l >>= k) (r >>= k)
BoolOr l r >>= k = BoolOr (l >>= k) (r >>= k)
BoolEQ l r >>= k = BoolEQ (l >>= k) (r >>= k)
BoolNE l r >>= k = BoolNE (l >>= k) (r >>= k)
BoolIf x y z >>= k = BoolIf (x >>= k) (y >>= k) (z >>= k)
Natural >>= _ = Natural
NaturalLit n >>= _ = NaturalLit n
NaturalFold >>= _ = NaturalFold
NaturalIsZero >>= _ = NaturalIsZero
NaturalEven >>= _ = NaturalEven
NaturalOdd >>= _ = NaturalOdd
NaturalPlus l r >>= k = NaturalPlus (l >>= k) (r >>= k)
NaturalTimes l r >>= k = NaturalTimes (l >>= k) (r >>= k)
Integer >>= _ = Integer
IntegerLit n >>= _ = IntegerLit n
Double >>= _ = Double
DoubleLit n >>= _ = DoubleLit n
Text >>= _ = Text
TextLit t >>= _ = TextLit t
TextAppend l r >>= k = TextAppend (l >>= k) (r >>= k)
TextConcat >>= _ = TextConcat
List >>= _ = List
ListLit t es >>= k = ListLit (t >>= k) (fmap (>>= k) es)
ListBuild >>= _ = ListBuild
ListFold >>= _ = ListFold
ListLength >>= _ = ListLength
ListHead >>= _ = ListHead
ListLast >>= _ = ListLast
ListIndexed >>= _ = ListIndexed
ListReverse >>= _ = ListReverse
ListAppend l r >>= k = ListAppend (l >>= k) (r >>= k)
ListConcat >>= _ = ListConcat
Maybe >>= _ = Maybe
MaybeLit t es >>= k = MaybeLit (t >>= k) (fmap (>>= k) es)
MaybeFold >>= _ = MaybeFold
Record kts >>= k = Record (Data.Map.fromAscList kts')
where
kts' = [ (k', t >>= k) | (k', t) <- Data.Map.toAscList kts ]
RecordLit kvs >>= k = RecordLit (Data.Map.fromAscList kvs')
RecordLit kvs >>= k = RecordLit (Data.Map.fromAscList kvs')
where
kvs' = [ (k', v >>= k) | (k', v) <- Data.Map.toAscList kvs ]
Field r x >>= k = Field (r >>= k) x
Embed r >>= k = k r
Pattern kts >>= k = Pattern (Data.Map.fromAscList kts')
where
kts' = [ (k', t >>= k) | (k', t) <- Data.Map.toAscList kts ]
PatternLit k' v kvs >>= k =
PatternLit k' (v >>= k) (Data.Map.fromAscList kvs')
where
kvs' = [ (k'', v' >>= k) | (k'', v') <- Data.Map.toAscList kvs ]
Field r x >>= k = Field (r >>= k) x
Embed r >>= k = k r
match :: Var -> Var -> [(Text, Text)] -> Bool
match (V xL nL) (V xR nR) [] =
@ -374,7 +385,17 @@ propEqual eL0 eR0 = State.evalState (go (normalize eL0) (normalize eR0)) []
go Text Text = return True
go List List = return True
go Maybe Maybe = return True
go (Record ktsL0) (Record ktsR0) = do
go (Record ktsL0) (Record ktsR0) = do
let loop ((kL, tL):ktsL) ((kR, tR):ktsR)
| kL == kR = do
b <- go tL tR
if b
then loop ktsL ktsR
else return False
loop [] [] = return True
loop _ _ = return False
loop (Data.Map.toList ktsL0) (Data.Map.toList ktsR0)
go (Pattern ktsL0) (Pattern ktsR0) = do
let loop ((kL, tL):ktsL) ((kR, tR):ktsR)
| kL == kR = do
b <- go tL tR
@ -533,6 +554,10 @@ buildExpr6 (RecordLit a) =
buildRecordLit a
buildExpr6 (Record a) =
buildRecord a
buildExpr6 (Pattern a) =
buildPattern a
buildExpr6 (PatternLit a b c) =
buildPatternLit a b c
buildExpr6 (Embed a) =
build a
buildExpr6 (Field a b) =
@ -580,6 +605,22 @@ buildRecord a | Data.Map.null a =
buildRecord a =
"{ " <> buildFieldTypes (Data.Map.toList a) <> " }"
buildPattern :: Buildable a => Map Text (Expr a) -> Builder
buildPattern a | Data.Map.null a =
"<:>"
buildPattern a =
"< " <> buildFieldTypes (Data.Map.toList a) <> " >"
buildPatternLit :: Buildable a => Text -> Expr a -> Map Text (Expr a) -> Builder
buildPatternLit a b c =
"< "
<> build a
<> " = "
<> buildExpr0 b
<> ", "
<> buildFieldTypes (Data.Map.toList c)
<> " >"
buildFieldTypes :: Buildable a => [(Text, Expr a)] -> Builder
buildFieldTypes [] = ""
buildFieldTypes [a] = buildFieldType a
@ -610,6 +651,7 @@ data TypeMessage
| InvalidPredicate (Expr X) (Expr X)
| IfBranchMismatch (Expr X) (Expr X) (Expr X) (Expr X)
| InvalidFieldType Text (Expr X)
| InvalidVariantType Text (Expr X)
| NotARecord Text (Expr X) (Expr X)
| MissingField Text (Expr X)
| CantAnd Bool (Expr X) (Expr X)
@ -1020,7 +1062,28 @@ You provided a record type with a key named:
$txt0
... annotated with the following expression which is not a type:
{{ ... : $txt1, ... }}
{ ... : $txt1, ... }
-- ^ This needs to be a type
You can fix the problem by changing the annotation to a type
|]
where
txt0 = Text.toStrict (pretty k )
txt1 = Text.toStrict (pretty expr0)
build (InvalidVariantType k expr0) =
Builder.fromText [NeatInterpolation.text|
Error: Invalid type of variant
Explanation: Every pattern type has an annotated type for each variant
However, variants *cannot* be annotated with expressions other than types
You provided a variant type with a variant named:
$txt0
... annotated with the following expression which is not a type:
< ... : $txt1, ... >
-- ^ This needs to be a type
You can fix the problem by changing the annotation to a type
@ -1035,9 +1098,9 @@ Error: Invalid record access
Explanation: You can only access fields on records, like this:
{ foo = True, bar = "ABC" }.foo -- This is valid ...
{ foo = True, bar = "ABC" }.foo -- This is valid ...
λ(r : {{ foo : Bool, bar : Text }}) r.foo -- ... and so is this
λ(r : { foo : Bool, bar : Text }) r.foo -- ... and so is this
... but you *cannot* access fields on non-record expressions, like this:
@ -1063,9 +1126,9 @@ Error: Missing record field
Explanation: You can only retrieve record fields if they are present
{ foo = True, bar = "ABC" }.foo -- This is valid ...
{ foo = True, bar = "ABC" }.foo -- This is valid ...
λ(r : {{ foo : Bool, bar : Text }}) r.foo -- ... and so is this
λ(r : { foo : Bool, bar : Text }) r.foo -- ... and so is this
... but you *cannot* access fields missing from a record:
@ -1361,6 +1424,13 @@ shift d v (Record kts) = Record (Data.Map.fromAscList kts')
shift d v (RecordLit kvs) = RecordLit (Data.Map.fromAscList kvs')
where
kvs' = [ (k, shift d v v') | (k, v') <- Data.Map.toList kvs ]
shift d v (Pattern kts) = Pattern (Data.Map.fromAscList kts')
where
kts' = [ (k, shift d v t) | (k, t) <- Data.Map.toList kts ]
shift d v (PatternLit k u kvs) = PatternLit k u' (Data.Map.fromAscList kvs')
where
u' = shift d v u
kvs' = [ (k, shift d v u'') | (k, u'') <- Data.Map.toList kvs ]
shift d v (Field a b) = Field a' b
where
a' = shift d v a
@ -1467,6 +1537,13 @@ subst x e (Record kts) = Record (Data.Map.fromAscList kts')
subst x e (RecordLit kvs) = RecordLit (Data.Map.fromAscList kvs')
where
kvs' = [ (k, subst x e v) | (k, v) <- Data.Map.toList kvs ]
subst x e (Pattern kts) = Pattern (Data.Map.fromAscList kts')
where
kts' = [ (k, subst x e t) | (k, t) <- Data.Map.toList kts ]
subst x e (PatternLit k v kvs) = PatternLit k v' (Data.Map.fromAscList kvs')
where
v' = subst x e v
kvs' = [ (k', subst x e v'') | (k', v'') <- Data.Map.toList kvs ]
subst x e (Field a b) = Field a' b
where
a' = subst x e a
@ -1780,7 +1857,7 @@ typeWith _ MaybeFold = do
(Pi "maybe" (Const Type)
(Pi "just" (Pi "_" "a" "maybe")
(Pi "nothing" "maybe" "maybe") ) ) ) )
typeWith ctx e@(Record kts ) = do
typeWith ctx e@(Record kts ) = do
let process (k, t) = do
s <- fmap normalize (typeWith ctx t)
case normalize s of
@ -1788,12 +1865,23 @@ typeWith ctx e@(Record kts ) = do
_ -> Left (TypeError ctx e (InvalidFieldType k t))
mapM_ process (Data.Map.toList kts)
return (Const Type)
typeWith ctx (RecordLit kvs ) = do
typeWith ctx (RecordLit kvs ) = do
let process (k, v) = do
t <- typeWith ctx v
return (k, t)
kts <- mapM process (Data.Map.toAscList kvs)
return (Record (Data.Map.fromAscList kts))
typeWith ctx e@(Pattern kts ) = do
let process (k, t) = do
s <- fmap normalize (typeWith ctx t)
case normalize s of
Const Type -> return ()
_ -> Left (TypeError ctx e (InvalidVariantType k t))
mapM_ process (Data.Map.toList kts)
return (Const Type)
typeWith ctx (PatternLit k v kts ) = do
t <- typeWith ctx v
return (Pattern (Data.Map.insert k t kts))
typeWith ctx e@(Field r x ) = do
t <- fmap normalize (typeWith ctx r)
case t of

View File

@ -58,6 +58,9 @@ tokens :-
"{" { emit OpenBrace }
"}" { emit CloseBrace }
"{:}" { emit EmptyRecord }
"<" { emit OpenAngle }
">" { emit CloseAngle }
"<:>" { emit EmptyPattern }
"[" { emit OpenBracket }
"]" { emit CloseBracket }
":" { emit Colon }
@ -219,6 +222,9 @@ data Token
| OpenBrace
| CloseBrace
| EmptyRecord
| OpenAngle
| CloseAngle
| EmptyPattern
| OpenBracket
| CloseBracket
| Colon
@ -288,6 +294,12 @@ instance Buildable Token where
= "}"
build EmptyRecord
= "{:}"
build OpenAngle
= "<"
build CloseAngle
= ">"
build EmptyPattern
= "<:>"
build OpenBracket
= "["
build CloseBracket

View File

@ -45,6 +45,9 @@ import qualified NeatInterpolation
'{' { Dhall.Lexer.OpenBrace }
'}' { Dhall.Lexer.CloseBrace }
'{:}' { Dhall.Lexer.EmptyRecord }
'<' { Dhall.Lexer.OpenAngle }
'>' { Dhall.Lexer.CloseAngle }
'<:>' { Dhall.Lexer.EmptyPattern }
'[' { Dhall.Lexer.OpenBracket }
']' { Dhall.Lexer.CloseBracket }
':' { Dhall.Lexer.Colon }
@ -243,6 +246,10 @@ Expr6
{ $1 }
| Record
{ $1 }
| Pattern
{ $1 }
| PatternLit
{ $1 }
| Import
{ Embed $1 }
| Expr6 '.' label
@ -302,6 +309,16 @@ Record
| '{:}'
{ Record (Data.Map.fromList []) }
Pattern
: '<' FieldTypes '>'
{ Pattern (Data.Map.fromList $2) }
| '<:>'
{ Pattern (Data.Map.fromList []) }
PatternLit
: '<' label '=' Expr0 ',' FieldTypes '>'
{ PatternLit $2 $4 (Data.Map.fromList $6) }
FieldTypes
: FieldTypesRev
{ reverse $1 }