-- Frap/Inductive.lean

section rewriting

variable (α : Type) (a b c d : α)  -- a, b, c, d are elements of some type

/-
## Rewriting

Recall our equality proof from last time.
-/

example : a = b → c = b → c = d → a = d := by
  intro hab hcb hcd
  apply Eq.trans
  . exact hab
  . apply Eq.trans
    . apply Eq.symm
      exact hcb
    . exact hcd

/-
Notice that in each subgoal, we are attempting to use a hypothesis by way of an equality property.
For example, we invoke the transitive property on `a = d` so that we can use the assumption `a = b` and be left with `b = d` to prove.
In effect, we are substituting `b` for `a` in the goal.

This substitution operation can be seen as rewriting some term in the goal with another, via an equality in the hypothesis.
This rewriting operation is so common that Lean provides a `rw` tactic to do so.
It replaces equals for equals, which could be an equality (`=`) or equivalence (`↔`).

Be default, it rewrites the left-hand side with the right-hand side.
For right-to-left rewriting, a left arrow needs to be indicated before the hypothesis (`←`, typed with `\<-` shortcut) .
-/

example : a = b → c = b → c = d → a = d := by
  intro hab hcb hcd
  rw [hab]
  rw [← hcd]
  rw [hcb]

end rewriting

/-
## reflexivity tactic

One of the most powerful tactics is the _reflexivity_ tactic, written `rfl` in Lean.
It will attempt to conclude that both sides of an equality goal is indeed equal, up to some trivial computation, such as expansion of definitions and function applications.
-/

example : 2 + 5 = 7 := by
  rfl

example : ¬ Even = 3 := by
  intro h
  sorry

namespace Hidden

inductive Nat where
  | zero : Nat
  | succ : Nat → Nat

namespace Nat

def add (m n : Nat) : Nat :=
  match n with
  | zero    => m
  | succ n' => succ (add m n')

def mul (m n : Nat) : Nat :=
  match n with
  | zero    => zero
  | succ n' => add (mul m n') m

instance : Add Nat where
  add := add

instance : Mul Nat where
  mul := mul

end Nat

end Hidden

section opendemo

open Nat

end opendemo

namespace Hidden

namespace Nat

end Nat

end Hidden

namespace Hidden

namespace Nat

-- Repository definitions used:
content: ...

-- Repository lemmas used:
content: theorem List.getElem_append_left{α : Type u_1} {l₁ l₂ : List α} {i : Nat} (hn : i < l₁.length) :\n(l₁ ++ l₂)[i] = l₁[i]

-- Local definitions used:
content: inductive Nat where
  | zero : Nat
  | succ : Nat → Nat

content: def add (m n : Nat) : Nat :=
  match n with
  | zero    => m
  | succ n' => succ (add m n')

-- Local lemmas used:
content: theorem add_succ (m n : Nat) : m + succ n = succ (m + n)

content: theorem add_assoc (m n k : Nat) : m + n + k = m + (n + k)

content: theorem mul_succ (m n : Nat) : m * succ n = add (m * n) m

content: theorem add_infix (m n : Nat) : m.add n = m + n

-- Target theorem and proof:
theorem mul_assoc (m n k : Nat) : m * n * k = m * (n * k)
:= by
  induction k with
  | zero => rfl
  | succ k' ih =>
      rw [mul_succ, mul_succ, ih, add_infix, add_infix]
      have nat_distrib (m n k : Nat)
            : m * n + m * k = m * (n + k) := by
        -- distributive property from left
        induction k with
        | zero => rfl
        | succ k' ih =>
            rw [mul_succ, add_succ, mul_succ, add_infix, add_infix, ← add_assoc, ih]
      rw [nat_distrib]