namespace Ex1

def f (n : Nat) : Option { r : Nat // r ≤ n } :=
  match n with
  | 0   => some ⟨0, Nat.le_refl _⟩
  | n+1 => match f n with
    | some ⟨m, h₁⟩ =>
      have : m < n+1 := Nat.lt_of_le_of_lt h₁ (Nat.lt_succ_self _)
      match f m with
      | some ⟨r, h₂⟩ => some ⟨r, Nat.le_trans h₂ (Nat.le_trans h₁ (Nat.le_succ _))⟩
      | none => none
    | none => none

end Ex1

namespace Ex2

def f (n : Nat) : Option { r : Nat // r ≤ n } :=
  if h : n = 0 then
    some ⟨0, h ▸ Nat.le_refl _⟩
  else
    match f (n-1) with
    | some ⟨m, h₁⟩ =>
      have : m < n := Nat.lt_of_le_of_lt h₁ (Nat.pred_lt h)
      match f m with
      | some ⟨r, h₂⟩ => some ⟨r, Nat.le_trans h₂ (Nat.le_trans h₁ (Nat.pred_le _))⟩
      | none => none
    | none => none

end Ex2

namespace Ex3

def f' (n : Nat) : Option { r : Nat // r ≤ n } :=
  match n with
  | 0   => some ⟨0, Nat.le_refl _⟩
  | n+1 => match f' n with
    | some ⟨m, h₁⟩ =>
      have : m < n+1 := Nat.lt_of_le_of_lt h₁ (Nat.lt_succ_self _)
      match f' m with
      | some ⟨r, h₂⟩ => some ⟨r, Nat.le_trans h₂ (Nat.le_trans h₁ (Nat.le_succ _))⟩
      | none => none
    | none => none

theorem f'_ne_none (n : Nat) : f' n ≠ none := by
  match n with
  | 0   => simp [f']
  | n+1 =>
    simp [f']
    have ih₁ := f'_ne_none n
    split
    next m h₁ he =>
      have : m < n+1 := Nat.lt_of_le_of_lt h₁ (Nat.lt_succ_self _)
      have ih₂ := f'_ne_none m
      split
      next => simp
      next h => contradiction
    next => contradiction

def f (n : Nat) : Option Nat :=
  match f' n with
  | some r => some r.1
  | none => none

theorem f_eq (n : Nat) :
        f n = match n with
          | 0 => some 0
          | n => match f (n - 1) with
            | some m => f m
            | none => none := by
  unfold f
  split
  next r h =>
    revert h
    split <;> try simp [f']
    next => intro h; subst h; simp
    next hne =>
      cases n <;> simp [f']
      next => contradiction
      next n _ =>
       split <;> try simp
       next r hrn h₁ =>
         split <;> simp
         next => intro he; subst he; simp [*]
  next h_eq_none =>
    have hne := f'_ne_none n
    contradiction

end Ex3
