module Martes where

{- Propositional logic in Agda -}

prop : Set₁
prop = Set

{- Proving some basic combinators. -}

K : {P Q : prop}  P  Q  P
K x y = x

S : {P Q R : prop}  (P  Q  R)  (P  Q)  P  R
S pqr pq p = pqr p (pq p) 

{- S, K are sufficent to prove all other tautologies involving only →. -}

I : {P : prop}  P  P
I x = x

B : {P Q R : prop}  (P  Q)  (Q  R)  P  R
B = λ pq qr p  qr (pq p)

C : {P Q R : prop}  (P  Q  R)  Q  P  R
C = λ x x' x0  x x0 x'

{- S, K are sufficent to prove all other tautologies involving only →. -}

I' : {P : prop}  P  P
I' {P} = S K (K {Q = P})


--Too hard for me.
CB' : {P Q R : prop}  (Q  R)  (P  Q)   P  R
CB' = S (K S) K

C' : {P Q R : prop}  (P  Q  R)  Q  P  R
C' = S (S (K S) (S (K K) S)) (K K)

B' : {P Q R : prop}  (P  Q)  (Q  R)  P  R
B' = C' CB'

{- draw the truth table and then try to prove it -}

{-
P : {P Q : prop} → ((P → Q) → P) → P
P = {!!}

Pierces' formula is uprovable.
-}

{- Defining other connectives -}

data _∧_ (P Q : prop) : prop where
  _,_ : P  Q  P  Q

infixr 2 _∧_
{- C-c C-, gives you the current "proof state" -}
∧-comm : {P Q : prop}  P  Q  Q  P
∧-comm (p , q) = q , p

data _∨_ (P Q : prop) : prop where
    left : P  P  Q
    right : Q  P  Q

distrib→ : {P Q R : prop}  P  (Q  R)  (P  Q)  (P  R)
distrib→ (p , left q) = left (p , q)
distrib→ (p , right r) = right (p , r)

distrib← : {P Q R : prop}  (P  Q)  (P  R)  P  (Q  R)
distrib← (left (p , q)) = p , left q
distrib← (right (p , r)) = p , right r

{- how do the two programs relate?
   there is more than just if and only iff.
 -}

_⇔_ : prop  prop  prop
P  Q = (P  Q)  (Q  P)

infixr 0 _⇔_

distrib⇔ : {P Q R : prop}  P  (Q  R)  (P  Q)  (P  R)
distrib⇔ = distrib→ , distrib←

curry→ : {P Q R : prop}  (P  Q  R)  (P  Q  R)
curry→ pqr p q = pqr (p , q)

curry← : {P Q R : prop}  (P  Q  R)  (P  Q  R)
curry← pqr (p , q) = pqr p q

curry⇔ : {P Q R : prop}  (P  Q  R)  (P  Q  R)
curry⇔ = curry→ , curry←

∨∧→ : {P Q R : prop}  (P  Q  R)  ((P  R)  (Q  R))
∨∧→ pqr =  p  pqr (left p)) , λ q  pqr (right q)

∨∧← : {P Q R : prop}  ((P  R)  (Q  R))  (P  Q  R) 
∨∧← (pr , qr) (left p) = pr p
∨∧← (pr , qr) (right q) = qr q  

∨∧ : {P Q R : prop}  (P  Q  R)  ((P  R)  (Q  R))
∨∧ = ∨∧→ , ∨∧←

{- some combinators -}

fst : {A B : prop}  A  B  A
fst (a , b) = a

snd : {A B : prop}  A  B  B
snd (a , b) = b

case : {A B C : prop}  (A  C)  (B  C)  A  B  C
case ac bc (left a) = ac a
case ac bc (right b) = bc b

or-com : {P Q : prop}  P  Q  Q  P
or-com = case right left

{- a different equivalence -}

copy : {A : prop}  A  A  A
copy =  x  (x , x)) ,  x  fst x)


{- challenge: reprove distrib only with combinators. -}

{-
distribC : {P Q R : prop} → P ∧ (Q ∨ R) → (P ∧ Q) ∨ (P ∧ R)
distribC = {!!}

--to hard for me.
-}

{- introduce true (⊤) and false (⊥) -}

{- \top = ⊤ -}
data  : prop where
  tt : 

{- \bot = ⊥ -}
data  : prop where
{- this space is intentionally left blank. -}

efq : {P : prop}    P
efq ()

¬ : prop  prop
¬ P = P  

contradict : {P : prop}  ¬ (P  ¬ P)
contradict (p , np) = np p

contrapos : {P Q : prop}  (P  Q)  ¬ Q  ¬ P
contrapos pq nq p = nq (pq p)

paradox : {P : prop}  ¬ (P  ¬ P) 
paradox (pnp , npp) = pnp (npp  x  pnp x x)) (npp  x  pnp x x))

{- Let's prove the de Morgan laws -}

deMorgan¬∨ : {P Q : prop}  ¬ (P  Q)  ¬ P  ¬ Q 
deMorgan¬∨ npq =  p  npq (left p)) , λ q  npq (right q)
  
deMorgan¬∧¬ : {P Q : prop}  (¬ P)  (¬ Q)  ¬ (P  Q)
deMorgan¬∧¬ (np , nq) (left p) = np p
deMorgan¬∧¬ (np , nq) (right q) = nq q
  
deMorgan¬∨¬ : {P Q : prop}  (¬ P)  (¬ Q)  ¬ (P  Q)
deMorgan¬∨¬ (left np) (p , q) = np p
deMorgan¬∨¬ (right nq) (p , q) = nq q

{-
deMorgan¬∧ : {P Q : prop} → ¬ (P ∧ Q) → (¬ P) ∨ (¬ Q)
deMorgan¬∧ npq = {!!}

the last de Morgan formula is unprovable!
-}

{- on classical vs intuitionistic reasoning. -}

{-
tnd : {P : prop} → P ∨ ¬ P
tnd = {!!}
Tertium non datur (excluded middle) is unprovable.
-}

¬¬ : prop  prop
¬¬ P = ¬ (¬ P)

pnnp : {P : prop}  P  ¬¬ P 
pnnp p np = np p
{-
raa : {P : prop} → ¬¬ P → P
raa nnp = {!!}
reductio ad absurdo (indirect proof)
is unprovable.
-}

¬¬tnd : {P : prop}  ¬¬ (P  ¬ P)
¬¬tnd npnp = npnp (right  p  npnp (left p)))

TND : Set₁
TND = {P : prop}  P  ¬ P

RAA : Set₁
RAA = {P : prop}  ¬¬ P  P

RAA→TND : RAA  TND
RAA→TND raa = raa ¬¬tnd

TND→RND : TND  RAA
TND→RND tnd {P} nnp with tnd {P}
TND→RND tnd nnp | left p = p
TND→RND tnd nnp | right np = efq (nnp np)

ret¬¬ : {P : prop}  P  ¬¬ P
ret¬¬ p np = np p 

bind¬¬ : {P Q : prop}  ¬¬ P  (P  ¬¬ Q)  ¬¬ Q 
bind¬¬ nnp pnnq nq = nnp  p  pnnq p nq)

map¬¬ : {P Q : prop}  ¬¬ P  (P  Q)  ¬¬ Q
map¬¬ np pq = bind¬¬ np  p  ret¬¬ (pq p))

app¬¬ : {P Q : prop}  ¬¬ (P  Q)  ¬¬ P  ¬¬ Q
app¬¬ nnpq nnp = bind¬¬ nnpq  pq  bind¬¬ nnp  p  ret¬¬ (pq p)))

∧¬¬-1 : {P Q : prop}  ¬¬ (P  Q)  ¬¬ P  ¬¬ Q
∧¬¬-1 nnpq = map¬¬ nnpq fst , map¬¬ nnpq snd

∧¬¬-2 : {P Q : prop}  ¬¬ P  ¬¬ Q  ¬¬ (P  Q) 
∧¬¬-2 (nnp , nnq) = bind¬¬ nnp  p  map¬¬ nnq   q  p , q))

∧¬¬ : {P Q : prop}  ¬¬ (P  Q)  ¬¬ P  ¬¬ Q
∧¬¬ = ∧¬¬-1 , ∧¬¬-2

{-
∨¬¬-1 : {P Q : prop} → ¬¬ (P ∨ Q) → ¬¬ P ∨ ¬¬ Q
∨¬¬-1 nnpq = {!!} 
is unprovable.
-}

∨¬¬-2 : {P Q : prop}  ¬¬ P  ¬¬ Q  ¬¬ (P  Q) 
∨¬¬-2 (left np) = map¬¬ np left
∨¬¬-2 (right nq) = map¬¬ nq right

{-
∨¬¬ : {P Q : prop} → ¬¬ (P ∨ Q) ⇔ ¬¬ P ∨ ¬¬ Q
∨¬¬ = {!!} 
is unprovable.
-}

¬¬deMorgan¬∧ : {P Q : prop}  ¬ (P  Q)  ¬¬ ((¬ P)  (¬ Q))
¬¬deMorgan¬∧ npq = λ x  x (left  x'  x (right  x0  npq (x' , x0)))))

{- Predicate logic -}

{- If A : Set,
      P : A → prop
   then ∀ a : A, P a
   is   (a : A) → P a
-}

∀∧ : {A : Set}{P Q : A  prop}  
  ((a : A)  P a  Q a)  ((a : A)  P a)  ((a : A)  Q a)
∀∧ pq =  a  fst (pq a)) ,  a  snd (pq a))

∧∀ : {A : Set}{P Q : A  prop}  
  ((a : A)  P a)  ((a : A)  Q a)  ((a : A)  P a  Q a)
∧∀ (ap , aq) = λ a  (ap a , aq a)

{-
∀∨ : {A : Set}{P Q : A → prop} → 
  ((a : A) → P a ∨ Q a) → ((a : A) → P a) ∨ ((a : A) → Q a)
∀∨ pq = {!!}
is even classically not true. -}

∨∀ : {A : Set}{P Q : A  prop}  
  ((a : A)  P a)  ((a : A)  Q a)  ((a : A)  P a  Q a)
∨∀ (left ap) = λ a  left (ap a)
∨∀ (right aq) = λ a  right (aq a)

{- Existential quantification: given a set A, and a predicate P : A → Prp
   ∀' A P : Prop means that P a is true (inhabited) for some a:A.
   A proof of this is a (depndent) pair (a , p) where a : A and 
   p : P a is a proof that P a is true (inhabited).
-}
data  (A : Set)(P : A  prop) : prop where
  _,_ : (a : A)  P a   A P

∃∧ : {A : Set}{P Q : A  prop}  
  ( A  a  P a  Q a))  ( A P)  ( A Q)
∃∧ (a , (p , q)) = (a , p) , (a , q)

{-
∧∃ : {A : Set}{P Q : A → prop} →
  (∃ A P) ∧ (∃ A Q) → (∃ A (λ a → P a ∧ Q a))
∧∃ x = {!!}
is even classically not true.
-}

∃∨ : {A : Set}{P Q : A  prop}  
  ( A  a  P a  Q a))  ( A P)  ( A Q)
∃∨ (a , left p) = left (a , p)
∃∨ (a , right q) = right (a , q)

∨∃ : {A : Set}{P Q : A  prop}  
  ( A P)  ( A Q)  ( A  a  P a  Q a))
∨∃ (left (a , p)) = a , left p
∨∃ (right (a , q)) = a , right q

{- the infinite deMorgan rules - which ones are provable? -}

{- ¬ (∃ x:A. P x) ⇔ ∀ x:A. ¬ P x -}

deMorgan¬∃ : {A : Set}{P : A  prop} 
           ¬ ( A  x  P x))  ((x : A)  ¬ (P x))
deMorgan¬∃ = λ x x' x0  x (x' , x0)

deMorgan∀¬ : {A : Set}{P : A  prop} 
           ((x : A)  ¬ (P x))  ¬ ( A  x  P x))
deMorgan∀¬ x (a , y) = x a y

{- ¬ (∀ x:A. P x) ⇔ ∃ x:A . ¬ P x -}

{-
deMorgan¬∀ : {A : Set}{P : A → prop} →
             ¬ ((x : A) → P x) → ∃ A (λ x → ¬ (P x))
deMorgan¬∀ = {!!}
-- unprovable.
-}

deMorgan∃¬ : {A : Set}{P : A  prop} 
            A  x  ¬ (P x))  ¬ ((x : A)  P x)
deMorgan∃¬ (a , y) = λ x  y (x a)

{- relating ∀ and ∃ -}

curry∀→ : {A : Set}{P : A  Set}{Q : prop}
          (( A P)  Q)  (a : A)  P a  Q
curry∀→ x = λ a x'  x (a , x')

curry∀← : {A : Set}{P : A  Set}{Q : prop}
          ((a : A)  P a  Q)  (( A P)  Q)
curry∀← x (a , y) = x a y

{- the axiom of choice -}

fst' : {A : Set}{P : A  prop}   A P  A
fst' (a , p) = a
{- Note that fst' really exploits the identification of prop and Set. -}

{- And show that the fst' satisfies the predicate: -}
snd' : {A : Set}{P : A  prop}  (p :  A P)  P (fst' p)
snd' (a , p) = p

ac : {A B : Set}{R : A  B  prop}  
     ((a : A)   B λ b  R a b)
       (A  B) λ f  (a : A)  R a (f a)
ac f =  a  fst' (f a)) , λ a  snd' (f a)

{- unprovable.
cac : {A B : Set}{R : A → B → prop} → 
     ((a : A) → ¬¬ (∃ B λ b → R a b))
     → ¬¬ (∃ (A → B) λ f → (a : A) → R a (f a))
cac h = {!!}

Counterexample:
 A = Turingmachines, B = Bool, R m b = b <-> m holds -}

dac : {A : Set}{B : A  Set}{R : (a : A)  B a  Set} 
       ((a : A)   (B a)  b  R a b))
        ((a : A)  B a)  f  (a : A)  R a (f a))
dac f =  a  fst' (f a)) , λ a  snd' (f a)