Skip to content

Commit

Permalink
Implement new simplifications for boolean logic (#316)
Browse files Browse the repository at this point in the history
... as standardized in dhall-lang/dhall-lang#109
  • Loading branch information
Gabriella439 authored Mar 7, 2018
1 parent 5a9126b commit d287f02
Show file tree
Hide file tree
Showing 14 changed files with 97 additions and 29 deletions.
1 change: 1 addition & 0 deletions dhall.cabal
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@ Extra-Source-Files:
tests/normalization/examples/Text/concatMap/*.dhall
tests/normalization/examples/Text/concatMapSep/*.dhall
tests/normalization/examples/Text/concatSep/*.dhall
tests/normalization/simplifications/*.dhall
tests/parser/*.dhall
tests/regression/*.dhall
tests/tutorial/*.dhall
Expand Down
36 changes: 27 additions & 9 deletions src/Dhall/Core.hs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ module Dhall.Core (
, normalize
, normalizeWith
, Normalizer
, judgmentallyEqual
, subst
, shift
, isNormalized
Expand Down Expand Up @@ -1107,7 +1108,7 @@ alphaNormalize (Embed a) =
However, `normalize` will not fail if the expression is ill-typed and will
leave ill-typed sub-expressions unevaluated.
-}
normalize :: Expr s a -> Expr t a
normalize :: Eq a => Expr s a -> Expr t a
normalize = normalizeWith (const Nothing)

{-| This function is used to determine whether folds like @Natural/fold@ or
Expand Down Expand Up @@ -1209,7 +1210,7 @@ denote (Embed a ) = Embed a
with those functions is not total either.
-}
normalizeWith :: Normalizer a -> Expr s a -> Expr t a
normalizeWith :: Eq a => Normalizer a -> Expr s a -> Expr t a
normalizeWith ctx e0 = loop (denote e0)
where
loop e = case e of
Expand Down Expand Up @@ -1356,32 +1357,40 @@ normalizeWith ctx e0 = loop (denote e0)
decide (BoolLit False) _ = BoolLit False
decide l (BoolLit True ) = l
decide _ (BoolLit False) = BoolLit False
decide l r = BoolAnd l r
decide l r
| judgmentallyEqual l r = l
| otherwise = BoolAnd l r
BoolOr x y -> decide (loop x) (loop y)
where
decide (BoolLit False) r = r
decide (BoolLit True ) _ = BoolLit True
decide l (BoolLit False) = l
decide _ (BoolLit True ) = BoolLit True
decide l r = BoolOr l r
decide l r
| judgmentallyEqual l r = l
| otherwise = BoolOr l r
BoolEQ x y -> decide (loop x) (loop y)
where
decide (BoolLit True ) r = r
decide l (BoolLit True ) = l
decide (BoolLit False) (BoolLit False) = BoolLit True
decide l r = BoolEQ l r
decide l r
| judgmentallyEqual l r = BoolLit True
| otherwise = BoolEQ l r
BoolNE x y -> decide (loop x) (loop y)
where
decide (BoolLit False) r = r
decide l (BoolLit False) = l
decide (BoolLit True ) (BoolLit True ) = BoolLit False
decide l r = BoolNE l r
decide l r
| judgmentallyEqual l r = BoolLit False
| otherwise = BoolNE l r
BoolIf bool true false -> decide (loop bool) (loop true) (loop false)
where
decide (BoolLit True ) l _ = l
decide (BoolLit False) _ r = r
decide b (BoolLit True) (BoolLit False) = b
decide b l r = BoolIf b l r
decide b l r
| judgmentallyEqual l r = l
| otherwise = BoolIf b l r
Natural -> Natural
NaturalLit n -> NaturalLit n
NaturalFold -> NaturalFold
Expand Down Expand Up @@ -1525,6 +1534,15 @@ normalizeWith ctx e0 = loop (denote e0)
Note _ e' -> loop e'
Embed a -> Embed a

{-| Returns `True` if two expressions are α-equivalent and β-equivalent and
`False` otherwise
-}
judgmentallyEqual :: Eq a => Expr s a -> Expr t a -> Bool
judgmentallyEqual eL0 eR0 = alphaBetaNormalize eL0 == alphaBetaNormalize eR0
where
alphaBetaNormalize :: Eq a => Expr s a -> Expr () a
alphaBetaNormalize = alphaNormalize . normalize

-- | Use this to wrap you embedded functions (see `normalizeWith`) to make them
-- polymorphic enough to be used.
type Normalizer a = forall s. Expr s a -> Maybe (Expr s a)
Expand Down
32 changes: 12 additions & 20 deletions src/Dhall/TypeCheck.hs
Original file line number Diff line number Diff line change
Expand Up @@ -58,14 +58,6 @@ rule Type Type = return Type
rule Kind Kind = return Kind
rule Kind Type = return Type

judgmentallyEqual :: Eq a => Expr s a -> Expr t a -> Bool
judgmentallyEqual eL0 eR0 = alphaBetaNormalize eL0 == alphaBetaNormalize eR0
where
alphaBetaNormalize :: Expr s a -> Expr X a
alphaBetaNormalize =
Dhall.Core.alphaNormalize
. Dhall.Core.normalize

{-| Type-check an expression and return the expression's type if type-checking
succeeds or an error if type-checking fails
Expand Down Expand Up @@ -131,7 +123,7 @@ typeWithA tpa = loop
Pi x _A _B -> return (x, _A, _B)
_ -> Left (TypeError ctx e (NotAFunction f tf))
_A' <- loop ctx a
if judgmentallyEqual _A _A'
if Dhall.Core.judgmentallyEqual _A _A'
then do
let a' = Dhall.Core.shift 1 (V x 0) a
let _B' = Dhall.Core.subst (V x 0) a' _B
Expand All @@ -148,7 +140,7 @@ typeWithA tpa = loop
_ <- loop ctx _A0
let nf_A0 = Dhall.Core.normalize _A0
let nf_A1 = Dhall.Core.normalize _A1
if judgmentallyEqual _A0 _A1
if Dhall.Core.judgmentallyEqual _A0 _A1
then return ()
else Left (TypeError ctx e (AnnotMismatch a0 nf_A0 nf_A1))
Nothing -> return ()
Expand All @@ -161,7 +153,7 @@ typeWithA tpa = loop
_ <- loop ctx t

t' <- loop ctx x
if judgmentallyEqual t t'
if Dhall.Core.judgmentallyEqual t t'
then do
return t
else do
Expand Down Expand Up @@ -237,7 +229,7 @@ typeWithA tpa = loop
Const Type -> return ()
_ -> Left (TypeError ctx e (IfBranchMustBeTerm False z tz ttz))

if judgmentallyEqual ty tz
if Dhall.Core.judgmentallyEqual ty tz
then return ()
else Left (TypeError ctx e (IfBranchMismatch y z ty tz))
return ty
Expand Down Expand Up @@ -335,7 +327,7 @@ typeWithA tpa = loop
_ -> Left (TypeError ctx e (InvalidListType t))
flip traverseWithIndex_ xs (\i x -> do
t' <- loop ctx x
if judgmentallyEqual t t'
if Dhall.Core.judgmentallyEqual t t'
then return ()
else do
let nf_t = Dhall.Core.normalize t
Expand All @@ -351,7 +343,7 @@ typeWithA tpa = loop
_ -> Left (TypeError ctx e (InvalidListType t))
flip traverseWithIndex_ xs (\i x -> do
t' <- loop ctx x
if judgmentallyEqual t t'
if Dhall.Core.judgmentallyEqual t t'
then return ()
else do
let nf_t = Dhall.Core.normalize t
Expand All @@ -369,7 +361,7 @@ typeWithA tpa = loop
App List er -> return er
_ -> Left (TypeError ctx e (CantListAppend r tr))

if judgmentallyEqual el er
if Dhall.Core.judgmentallyEqual el er
then return (App List el)
else Left (TypeError ctx e (ListAppendMismatch el er))
loop _ ListBuild = do
Expand Down Expand Up @@ -410,7 +402,7 @@ typeWithA tpa = loop
_ -> Left (TypeError ctx e (InvalidOptionalType t))
forM_ xs (\x -> do
t' <- loop ctx x
if judgmentallyEqual t t'
if Dhall.Core.judgmentallyEqual t t'
then return ()
else do
let nf_t = Dhall.Core.normalize t
Expand Down Expand Up @@ -538,10 +530,10 @@ typeWithA tpa = loop
Just tX ->
case tX of
Pi _ tY' t' -> do
if judgmentallyEqual tY tY'
if Dhall.Core.judgmentallyEqual tY tY'
then return ()
else Left (TypeError ctx e (HandlerInputTypeMismatch kY tY tY'))
if judgmentallyEqual t t'
if Dhall.Core.judgmentallyEqual t t'
then return ()
else Left (TypeError ctx e (InvalidHandlerOutputType kY t t'))
_ -> Left (TypeError ctx e (HandlerNotAFunction kY tX))
Expand Down Expand Up @@ -577,10 +569,10 @@ typeWithA tpa = loop
Just tX ->
case tX of
Pi _ tY' t' -> do
if judgmentallyEqual tY tY'
if Dhall.Core.judgmentallyEqual tY tY'
then return ()
else Left (TypeError ctx e (HandlerInputTypeMismatch kY tY tY'))
if judgmentallyEqual t t'
if Dhall.Core.judgmentallyEqual t t'
then return ()
else Left (TypeError ctx e (HandlerOutputTypeMismatch kX t kY t'))
_ -> Left (TypeError ctx e (HandlerNotAFunction kY tX))
Expand Down
11 changes: 11 additions & 0 deletions tests/Normalization.hs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ normalizationTests :: TestTree
normalizationTests =
testGroup "normalization"
[ examples
, simplifications
, constantFolding
, conversions
, shouldNormalize "Optional build/fold fusion" "optionalBuildFold"
Expand Down Expand Up @@ -154,6 +155,16 @@ examples =
, shouldNormalize "Text/concatSep" "./examples/Text/concatSep/1"
]

simplifications :: TestTree
simplifications =
testGroup "Simplifications"
[ shouldNormalize "if/then/else" "./simplifications/ifThenElse"
, shouldNormalize "||" "./simplifications/or"
, shouldNormalize "&&" "./simplifications/and"
, shouldNormalize "==" "./simplifications/eq"
, shouldNormalize "!=" "./simplifications/ne"
]

constantFolding :: TestTree
constantFolding =
testGroup "folding of constants"
Expand Down
6 changes: 6 additions & 0 deletions tests/normalization/simplifications/andA.dhall
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{ example0 = λ(x : Bool) x && True
, example1 = λ(x : Bool) True && x
, example2 = λ(x : Bool) x && False
, example3 = λ(x : Bool) False && x
, example4 = λ(x : Bool) x && x
}
6 changes: 6 additions & 0 deletions tests/normalization/simplifications/andB.dhall
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{ example0 = λ(x : Bool) x
, example1 = λ(x : Bool) x
, example2 = λ(x : Bool) False
, example3 = λ(x : Bool) False
, example4 = λ(x : Bool) x
}
4 changes: 4 additions & 0 deletions tests/normalization/simplifications/eqA.dhall
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{ example0 = λ(x : Bool) x == True
, example1 = λ(x : Bool) True == x
, example2 = λ(x : Bool) x == x
}
4 changes: 4 additions & 0 deletions tests/normalization/simplifications/eqB.dhall
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{ example0 = λ(x : Bool) x
, example1 = λ(x : Bool) x
, example2 = λ(x : Bool) True
}
3 changes: 3 additions & 0 deletions tests/normalization/simplifications/ifThenElseA.dhall
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{ example0 = λ(x : Bool) if x then True else False
, example1 = λ(x : Bool) λ(y : Text) if x then y else y
}
3 changes: 3 additions & 0 deletions tests/normalization/simplifications/ifThenElseB.dhall
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{ example0 = λ(x : Bool) x
, example1 = λ(x : Bool) λ(y : Text) y
}
4 changes: 4 additions & 0 deletions tests/normalization/simplifications/neA.dhall
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{ example0 = λ(x : Bool) x != False
, example1 = λ(x : Bool) False != x
, example2 = λ(x : Bool) x != x
}
4 changes: 4 additions & 0 deletions tests/normalization/simplifications/neB.dhall
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{ example0 = λ(x : Bool) x
, example1 = λ(x : Bool) x
, example2 = λ(x : Bool) False
}
6 changes: 6 additions & 0 deletions tests/normalization/simplifications/orA.dhall
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{ example0 = λ(x : Bool) x || True
, example1 = λ(x : Bool) True || x
, example2 = λ(x : Bool) x || False
, example3 = λ(x : Bool) False || x
, example4 = λ(x : Bool) x || x
}
6 changes: 6 additions & 0 deletions tests/normalization/simplifications/orB.dhall
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{ example0 = λ(x : Bool) True
, example1 = λ(x : Bool) True
, example2 = λ(x : Bool) x
, example3 = λ(x : Bool) x
, example4 = λ(x : Bool) x
}

0 comments on commit d287f02

Please sign in to comment.