#ifdef LANGUAGE_PTS_HAS_EQUALITY
#ifdef LANGUAGE_PTS_HAS_BOOL
#ifdef LANGUAGE_PTS_HAS_NAT
#ifdef LANGUAGE_PTS_HAS_SIGMA
#ifdef LANGUAGE_PTS_HAS_PROP
#define EQUALITY_EXAMPLES
{-# LANGUAGE OverloadedStrings, ScopedTypeVariables #-}
#endif
#endif
#endif
#endif
#endif
module Language.PTS.Examples.Equality (
#ifdef EQUALITY_EXAMPLES
    equalityScript,
    equivalenceScript,
    leibnizScript,
    inequalityScript,
#endif
    ) where
#ifdef EQUALITY_EXAMPLES
import Language.PTS
import Language.PTS.Bound
equalityScript :: forall s m. Script s m => m ()
equalityScript = do
    section_ "Non-dependent elimination: if"
    define_ "if"
        $$ forall_ "r" (TermBool ~> "r" ~> "r" ~> "r")
        $$ lams_ ["r", "b", "t", "f"]
              (Inf $ TermBoolElim "_" (liftH "r") "t" "f" "b")
    section_ "Negation, not"
    define_ "not"
        $$ TermBool ~> TermBool
        $$ lam_ "b" ("if" @@@ TermBool @@ "b" @@@ TermFalse @@@ TermTrue)
    example_ "not"
    example_ $ "not" @@@ TermTrue
    example_ $ "not" @@@ TermFalse
    section_ "Simple equality examples"
    example_ $$ Refl -:-
        Equality TermBool ("not" @@@ TermTrue) (Inf TermFalse)
    example_ $$ Refl -:-
        Equality TermBool ("not" @@@ TermFalse) (Inf TermTrue)
    section_ "Lemma: Not is involutive"
    let ty b = Equality TermBool b ("not" @@ ("not" @@ b))
    define_ "not-inv"
        $$ pi_ "b" TermBool (ty "b")
        $$ lam_ "b" (Inf $ TermBoolElim "x" (abstract1HSym "x" $ ty "x") Refl Refl "b")
    section_ "Example with exists"
    let ty2 :: TermInf s Sym -> TermInf s Sym
        ty2 x = sigma_ "y" TermBool (Equality TermBool (Inf x) ("not" @@ "y"))
    define_ "not-surj"
        $$ pi_ "x" TermBool (ty2 "x")
        $$ lam_ "x" (Inf $ TermBoolElim "b" (abstract1HSym "b" $ ty2 "b")
            (Pair (Inf TermFalse) Refl)
            (Pair (Inf TermTrue) Refl)
            "x")
equivalenceScript :: forall s m. Script s m => m ()
equivalenceScript = do
    section_ "Symmetry"
    define_ "SYM"
        $$ sort_ typeSort ~> sort_ typeSort
        $$ lam_ "A" (pi_ "x" "A" $ pi_ "y" "A" $ Equality "A" "x" "y" ~> Equality "A" "y" "x")
    let j_ u v w a p =  J (V3 (IrrSym u) (IrrSym v) (IrrSym w)) a (abstract3HSym u v w p)
    define_ "sym"
        $$ forall_ "A" ("SYM" @@ "A")
        $$ lams_ ["A","x","y","p"]
            (Inf $ j_ "u" "v" "w" "A" (Equality "A" "v" "u") (lam_ "q" Refl) "x" "y" "p")
    subsection_ "Example"
    define_ "nat-fold"
        $$ forall_ "r" (TermNat ~> ("r" ~> "r") ~> "r" ~> "r")
        $$ lams_ ["r", "n", "s", "z"]
              (Inf $ TermNatElim "_" (liftH "r") "z" (lam_ "l" "s") "n")
    define_ "succ"
        $$ TermNat ~> TermNat
        $$ lam_ "n" (Inf $ TermNatS "n")
    define_ "plus"
        $$ TermNat ~> TermNat ~> TermNat
        $$ lams_ ["x", "y"] ("nat-fold" @@@ TermNat @@ "x" @@ "succ" @@ "y")
    example_ $ Refl -:- Equality TermNat (3 + 1) (1 + 3)
    example_ $ "sym" @@@ TermNat @@ 3 + 1 @@ 1 + 3 @@ Refl
    section_ "Transitivity"
    define_ "TRANS"
        $$ sort_ typeSort ~> sort_ typeSort
        $$ lam_ "A" (pi_ "x" "A" $ pi_ "y" "A" $ pi_ "z" "A" $ Equality "A" "x" "y" ~> Equality "A" "y" "z" ~> Equality "A" "x" "z")
    define_ "trans"
        $$ forall_"A" ("TRANS" @@ "A")
        $$ lams_ ["A","x","y","z","p"]
            (Inf $ j_ "u" "v" "w" "A" (Equality "A" "v" "z" ~> Equality "A" "u" "z") (lams_ ["_", "r"] "r") "x" "y" "p")
    example_ $ "trans" @@@ TermNat @@ 1 + 3 @@ 2 + 2 @@ 3 + 1 @@ Refl
inequalityScript :: forall s m. Script s m => m ()
inequalityScript = do
    comment_ "Proving inequalities is difficult!"
    define_ "if1"
        $$ pi_ "r" (sort_ typeSortSort) (TermBool ~> "r" ~> "r" ~> "r")
        $$ lams_ ["r", "b", "t", "f"]
              (Inf $ TermBoolElim "_" (liftH "r") "t" "f" "b")
    comment_ "Important thing is to find proper motive for induction"
    let motive u v = "if1" @@ sort_ typeSort @@ u @@ ("if1" @@ sort_ typeSort @@ v @@@ Unit @@@ Empty) @@@ Unit
    define_ "motive"
        $$ TermBool ~> TermBool ~> sort_ typeSort
        $$ lams_ ["u","v"] (motive "u" "v")
    comment_ "With proper motive, proof is almost trivial"
    let j_ u v w a p =  J (V3 (IrrSym u) (IrrSym v) (IrrSym w)) a (abstract3HSym u v w p)
    define_ "true-is-not-false"
        $$ Equality TermBool (Inf TermTrue) (Inf TermFalse) ~> Empty
        $$ lams_ ["p"]
            (Inf $ j_ "u" "v" "w" TermBool
                ("motive" @@ "u" @@  "v")
                (lam_ "b" $ Inf $ TermBoolElim "c" (abstract1HSym "c" $ "motive" @@ "c" @@ "c") (Inf I) (Inf I) "b")
                (Inf TermTrue) (Inf TermFalse) "p")
    example_ "true-is-not-false"
leibnizScript :: forall s m. Script s m => m ()
leibnizScript = do
    section_ "Leibniz"
    comment_ "We can define Leibniz equality"
    comment_ "in the systems with impredicative bottom universe."
    comment_ "TODO: define CComega, and make conversions"
    define_ "Leibniz"
        $$ pi_ "A" (sort_ typeSort) ("A" ~> "A" ~> sort_ typeSort)
        
        $$ lams_ ["A","x","y"] (pi_ "C" ("A" ~> sort_ typeSort) $ "C" @@ "x" ~> "C" @@ "y")
    subsection_ "Reflexivity"
    define_ "REFL"
        $$ sort_ typeSort ~> sort_ typeSort
        $$ lam_ "A" (pi_ "x" "A" $ "Leibniz" @@ "A" @@ "x" @@ "x")
    define_ "refl1"
        $$ forall_ "A" ("REFL" @@ "A")
        $$ lams_ ["A","x","C","Cx"] "Cx"
    subsection_ "Symmetry"
    define_ "SYM"
        $$ sort_ typeSort ~> sort_ typeSort
        $$ lam_ "A" (pi_ "x" "A" $ pi_ "y" "A" $ "Leibniz" @@ "A" @@ "x" @@ "y" ~> "Leibniz" @@ "A" @@ "y" @@ "x")
    define_ "sym"
        $$ forall_ "A" ("SYM" @@ "A")
        $$ lams_ ["A","x","y","xy"]
            ("xy" @@ lam_ "z" ("Leibniz" @@ "A" @@ "z" @@ "x") @@ ("refl1" @@ "A" @@ "x"))
    subsection_ "Transitivity"
    comment_ "An exercise!"
#endif