variable (p q r : Prop)

-- commutativity of ∧ and ∨
example : p ∧ q ↔ q ∧ p :=
  ⟨λ ⟨p,q⟩ => ⟨q,p⟩, λ ⟨q,p⟩ => ⟨p,q⟩⟩

example : p ∨ q ↔ q ∨ p :=
  ⟨λ
    | Or.inl p => Or.inr p
    | Or.inr q => Or.inl q,
   λ
    | Or.inl q => Or.inr q
    | Or.inr p => Or.inl p⟩

-- associativity of ∧ and ∨
example : (p ∧ q) ∧ r ↔ p ∧ (q ∧ r) :=
  ⟨λ ⟨⟨p,q⟩,r⟩ => ⟨p,⟨q,r⟩⟩, λ ⟨p,⟨q,r⟩⟩ => ⟨⟨p,q⟩,r⟩⟩

example : (p ∨ q) ∨ r ↔ p ∨ (q ∨ r) :=
  ⟨λ
    | Or.inr r => Or.inr (Or.inr r)
    | Or.inl (Or.inr q) => Or.inr (Or.inl q)
    | Or.inl (Or.inl p) => Or.inl p,
  λ
    | Or.inl p => Or.inl (Or.inl p)
    | Or.inr (Or.inl q) => Or.inl (Or.inr q)
    | Or.inr (Or.inr r) => Or.inr r⟩

-- distributivity
example : p ∧ (q ∨ r) ↔ (p ∧ q) ∨ (p ∧ r) :=
  ⟨λ
    | ⟨p, Or.inl q⟩ => Or.inl ⟨p,q⟩
    | ⟨p, Or.inr r⟩ => Or.inr ⟨p,r⟩,
  λ
    | Or.inl ⟨p,q⟩ => ⟨p,Or.inl q⟩
    | Or.inr ⟨p,r⟩ => ⟨p,Or.inr r⟩⟩

example : p ∨ (q ∧ r) ↔ (p ∨ q) ∧ (p ∨ r) :=
  ⟨λ
    | Or.inl p => ⟨Or.inl p, Or.inl p⟩
    | Or.inr ⟨q,r⟩ => ⟨Or.inr q, Or.inr r⟩,
  λ
    | ⟨Or.inr q, Or.inr r⟩ => Or.inr ⟨q,r⟩
    | ⟨Or.inl p,        _⟩ => Or.inl p
    | ⟨       _, Or.inl p⟩ => Or.inl p⟩

-- other properties
example : (p → (q → r)) ↔ (p ∧ q → r) :=
  ⟨λ f ⟨p,q⟩ => f p q,λ f p q => f ⟨p,q⟩⟩

example : ((p ∨ q) → r) ↔ (p → r) ∧ (q → r) :=
  ⟨
    λ f =>  ⟨λ p => f (Or.inl p), λ q => f (Or.inr q)⟩,
    λ
      |⟨f, _⟩, Or.inl p => f p
      |⟨_, g⟩, Or.inr q => g q⟩

example : ¬(p ∨ q) ↔ ¬p ∧ ¬q :=
  ⟨λ f => ⟨λ p => f (Or.inl p), λ q => f (Or.inr q)⟩,
   λ
    | ⟨np, _⟩, Or.inl p => np p
    | ⟨_ ,nq⟩, Or.inr q => nq q⟩

example : ¬p ∨ ¬q → ¬(p ∧ q)
  | Or.inl np, ⟨p,_⟩ => np p
  | Or.inr nq, ⟨_,q⟩ => nq q

example : ¬(p ∧ ¬p) :=
  λ ⟨p,np⟩ => np p

example : p ∧ ¬q → ¬(p → q) :=
  λ ⟨p,nq⟩ ptoq => nq (ptoq p)

example : ¬p → (p → q) :=
  λ np p => absurd p np

example : (¬p ∨ q) → (p → q)
  | (Or.inl np), p => absurd p np
  | (Or.inr q), _ => q

example : p ∨ False ↔ p :=
  ⟨λ h => Or.elim h id False.elim, λ p => Or.inl p⟩

example : p ∧ False ↔ False :=
  ⟨λ ⟨_,f⟩ => f, λ f => False.elim f⟩

example : (p → q) → (¬q → ¬p) :=
 λ f nq p => absurd (f p) nq
