def f : Nat → Bool → Nat
  | 0,  true  => 1
  | 0,  false => 2
  | 1,  true => 3
  | 1,  _ => 4
  | x+2, true => f x true
  | x+2, b => f x (not b)

macro "urfl" : tactic => `(set_option smartUnfolding false in rfl)


theorem f_main_eq : f x b = f.match_1 (fun _ _ => Nat) x b (fun _ => 1) (fun _ => 2) (fun _ => 3) (fun _ => 4) (fun x => f x true) (fun x b => f x (not b)) := by
  split <;> (first | rfl | (conv => lhs; delta f; whnf; simp_match); try urfl)

#check @f_main_eq

def g : List Nat → List Nat → Nat
  | [],         y::ys => y
  | [],         ys    => 0
  | x1::x2::xs, ys    => g xs ys
  | x::xs,      y::ys => g xs ys + y
  | x::xs,      []    => g xs []

theorem g_main_eq (xs ys : List Nat) : g xs ys = g.match_1 (fun _ _ => Nat) xs ys (fun y ys => y) (fun _ => 0) (fun _ _ xs ys => g xs ys) (fun _ xs y ys => g xs ys + y) (fun _ xs => g xs []) := by
  split <;> (first | rfl | (conv => lhs; delta g; whnf; simp_match); try urfl)

#check @g_main_eq

def foo (xs : List Nat) : List Nat :=
  match xs with
  | []    => []
  | x::xs =>
    let y := 2 * x;
    match xs with
    | []    => []
    | x::xs => (y + x) :: foo xs

theorem foo_main_eq (xs : List Nat) : foo xs = foo.match_1 (fun _ => List Nat) xs (fun _ => []) (fun x xs => let y := 2*x; foo.match_1 (fun _ => List Nat) xs (fun _ => []) (fun x xs => (y + x)::foo xs)) := by
  split
  · rfl
  · split
    · rfl
    · rfl

#check @foo_main_eq
