{-# OPTIONS -w #-}
module Lambdabot.Plugin.Haskell.Free.Theorem where
import Lambdabot.Plugin.Haskell.Free.Type
import Lambdabot.Plugin.Haskell.Free.Expr
import Lambdabot.Plugin.Haskell.Free.Util
import Prelude hiding ((<>))
data Theorem
= ThForall Var Type Theorem
| ThImplies Theorem Theorem
| ThEqual Expr Expr
| ThAnd Theorem Theorem
deriving (Eq,Show)
precIMPLIES, precAND :: Int
precIMPLIES = 5
precAND = 3
instance Pretty Theorem where
prettyP p t = prettyTheorem p False t
prettyTheorem :: Int -> Bool -> Theorem -> Doc
prettyTheorem p fa th@(ThForall v t p1)
| fa = prettyForall p [v] p1
| otherwise = prettyP p p1
prettyTheorem p fa (ThImplies p1 p2)
= prettyParenIndent (p > precIMPLIES) (
prettyTheorem (precIMPLIES+1) True p1
$$ nest (-1) (text "=>")
$$ prettyTheorem precIMPLIES fa p2
)
prettyTheorem _ _ (ThEqual e1 e2)
= prettyP 0 e1 <+> text "=" <+> prettyP 0 e2
prettyTheorem p fa (ThAnd e1 e2)
= prettyParenIndent (p > precAND) (
prettyTheorem (precAND+1) fa e1 $$ text "&&"
$$ prettyTheorem precAND fa e2
)
prettyForall :: Int -> [Var] -> Theorem -> Doc
prettyForall p vs (ThForall v t p1)
= prettyForall p (v:vs) p1
prettyForall p vs th
= parens (
text "forall" <+> hsep [ text v | v <- reverse vs ] <> text "."
<+> prettyTheorem 0 True th
)
varInTheorem :: Var -> Theorem -> Bool
varInTheorem v (ThForall v' t p)
= v /= v' && varInTheorem v p
varInTheorem v (ThImplies p1 p2)
= varInTheorem v p1 || varInTheorem v p2
varInTheorem v (ThEqual e1 e2)
= varInExpr v e1 || varInExpr v e2
varInTheorem v (ThAnd e1 e2)
= varInTheorem v e1 || varInTheorem v e2
applySimplifierTheorem :: (Theorem -> Theorem) -> (Theorem -> Theorem)
applySimplifierTheorem s (ThForall v t p)
= ThForall v t (s p)
applySimplifierTheorem s (ThImplies p1 p2)
= ThImplies (s p1) (s p2)
applySimplifierTheorem s p@(ThEqual _ _)
= p
applySimplifierTheorem s p@(ThAnd p1 p2)
= ThAnd (s p1) (s p2)
peepholeSimplifyTheorem :: Theorem -> Theorem
peepholeSimplifyTheorem
= peepholeSimplifyTheorem' . applySimplifierTheorem peepholeSimplifyTheorem
peepholeSimplifyTheorem' :: Theorem -> Theorem
peepholeSimplifyTheorem' (ThForall v t p)
= case varInTheorem v p of
True -> ThForall v t p
False -> p
peepholeSimplifyTheorem' p@(ThAnd e1 e2)
= foldr1 ThAnd (flattenAnd e1 . flattenAnd e2 $ [])
where
flattenAnd (ThAnd e1 e2) = flattenAnd e1 . flattenAnd e2
flattenAnd e = (e:)
peepholeSimplifyTheorem' p
= p
peepholeSimplifyExpr :: Expr -> Expr
peepholeSimplifyExpr
= peepholeSimplifyExpr' . applySimplifierExpr peepholeSimplifyExpr
peepholeSimplifyExpr' :: Expr -> Expr
peepholeSimplifyExpr' (EApp (EBuiltin BId) e2)
= e2
peepholeSimplifyExpr' (EApp (EBuiltin (BMap _)) (EBuiltin BId))
= EBuiltin BId
peepholeSimplifyExpr' e
= e
foldEquality :: Theorem -> Theorem
foldEquality p@(ThForall _ _ _)
= case foldEquality' p [] of
Just p' -> p'
Nothing -> applySimplifierTheorem foldEquality p
where
foldEquality' (ThForall v t p) vts
= foldEquality' p ((v,t):vts)
foldEquality' (ThImplies (ThEqual (EVar v) e2) p) vts
| v `elem` map fst vts
= foldEquality'' vts (theoremSubst v e2 p)
foldEquality' (ThImplies (ThEqual e1 (EVar v)) p) vts
| v `elem` map fst vts
= foldEquality'' vts (theoremSubst v e1 p)
foldEquality' _ vts
= Nothing
foldEquality'' [] e
= Just e
foldEquality'' ((v,t):vts) e
= foldEquality'' vts (ThForall v t e)
foldEquality p
= applySimplifierTheorem foldEquality p
tryCurrying :: Theorem -> Theorem
tryCurrying p@(ThForall _ _ _)
= case tryCurrying' p [] of
Just p' -> p'
Nothing -> applySimplifierTheorem tryCurrying p
where
tryCurrying' (ThForall v t p) vts
= tryCurrying' p ((v,t):vts)
tryCurrying' (ThEqual e1 e2) vts
= case (traverseRight ECDot e1, traverseRight ECDot e2) of
((ctx1, EVar v1), (ctx2, EVar v2))
| v1 == v2 && v1 `elem` map fst vts
&& not (varInCtx v1 ctx1) && not (varInCtx v2 ctx2)
-> tryCurrying'' vts (ThEqual (untraverse ctx1)
(untraverse ctx2))
_ -> Nothing
tryCurrying' _ _
= Nothing
traverseRight ctx (EApp e1 e2)
= traverseRight (ECAppR e1 ctx) e2
traverseRight ctx e
= (ctx, e)
untraverse ECDot = EBuiltin BId
untraverse (ECAppR e1 ECDot)
= e1
untraverse (ECAppR e1 ctx)
= EApp (EApp (EVarOp FR 9 ".") (untraverse ctx)) e1
tryCurrying'' [] e
= Just e
tryCurrying'' ((v,t):vts) e
= tryCurrying'' vts (ThForall v t e)
tryCurrying p
= applySimplifierTheorem tryCurrying p
theoremSimplify :: Theorem -> Theorem
theoremSimplify
= iterateUntilFixpoint
(foldEquality
. iterateUntilFixpoint peephole
. tryCurrying
. iterateUntilFixpoint peephole
)
where
iterateUntilFixpoint s t
= findFixpoint (iterate s t)
peephole t = findFixpoint (iterate peepholeSimplifyTheorem t)
findFixpoint (x1:xs@(x2:_))
| x1 == x2 = x2
| otherwise = findFixpoint xs
theoremSubst :: Var -> Expr -> Theorem -> Theorem
theoremSubst v e (ThForall f t p)
= ThForall f t (theoremSubst v e p)
theoremSubst v e (ThImplies p1 p2)
= ThImplies (theoremSubst v e p1) (theoremSubst v e p2)
theoremSubst v e (ThEqual e1 e2)
= ThEqual (exprSubst v e e1) (exprSubst v e e2)
theoremSubst v e (ThAnd p1 p2)
= ThAnd (theoremSubst v e p1) (theoremSubst v e p2)