-- Mathlib/Computability/PartrecCode.lean
theorem hG : Primrec G

Proof state:
case hrf
a : Primrec fun a => ofNat (ℕ × Code) a.length
k✝ : Primrec fun a => (ofNat (ℕ × Code) a.1.length).1
n✝ : Primrec Prod.snd
k : Primrec fun a => (ofNat (ℕ × Code) a.1.1.length).1
n : Primrec fun a => a.1.2
k' : Primrec Prod.snd
c : Primrec fun a => (ofNat (ℕ × Code) a.1.1.length).2
⊢ Primrec fun a =>
    let z := (unpair a.1.1.2).1;
    let m := (unpair a.1.1.2).2;
    do
    let x ← Nat.Partrec.Code.lup a.1.1.1 ((ofNat (ℕ × Code) a.1.1.1.length).1, a.2.1) (Nat.pair z m)
    Nat.casesOn x (some m) fun x =>
        Nat.Partrec.Code.lup a.1.1.1 (a.1.2, (ofNat (ℕ × Code) a.1.1.1.length).2) (Nat.pair z (m + 1))

Tactic:
have L := (Primrec.fst.comp Primrec.fst).comp
  (Primrec.fst (α := (List (List (Option ℕ)) × ℕ) × ℕ)
    (β := Code × Option ℕ))

Result:
case hrf
a : Primrec fun a => ofNat (ℕ × Code) a.length
k✝ : Primrec fun a => (ofNat (ℕ × Code) a.1.length).1
n✝ : Primrec Prod.snd
k : Primrec fun a => (ofNat (ℕ × Code) a.1.1.length).1
n : Primrec fun a => a.1.2
k' : Primrec Prod.snd
c : Primrec fun a => (ofNat (ℕ × Code) a.1.1.length).2
L : Primrec fun a => a.1.1.1
⊢ Primrec fun a =>
    let z := (unpair a.1.1.2).1;
    let m := (unpair a.1.1.2).2;
    do
    let x ← Nat.Partrec.Code.lup a.1.1.1 ((ofNat (ℕ × Code) a.1.1.1.length).1, a.2.1) (Nat.pair z m)
    Nat.casesOn x (some m) fun x =>
        Nat.Partrec.Code.lup a.1.1.1 (a.1.2, (ofNat (ℕ × Code) a.1.1.1.length).2) (Nat.pair z (m + 1))

Proof state:
case hpc
a : Primrec fun a => ofNat (ℕ × Code) a.length
k✝¹ : Primrec fun a => (ofNat (ℕ × Code) a.1.length).1
n✝¹ : Primrec Prod.snd
k✝ : Primrec fun a => (ofNat (ℕ × Code) a.1.1.length).1
n✝ : Primrec fun a => a.1.2
k' : Primrec Prod.snd
c : Primrec fun a => (ofNat (ℕ × Code) a.1.1.length).2
L✝ : Primrec fun a => a.1.1.1
k : Primrec fun a => (ofNat (ℕ × Code) a.1.1.1.length).1
n : Primrec fun a => a.1.1.2
cf : Primrec fun a => a.2.1
cg : Primrec fun a => a.2.2.1
z✝ : Primrec fun a => (unpair a.1.1.2).1
L : Primrec fun a => a.1.1.1.1
z : Primrec fun a => (unpair a.1.1.1.2).1
y : Primrec Prod.snd
h₁ :
  Primrec fun a =>
    Nat.Partrec.Code.lup
      (a.1.1.1.1, (a.1.1.2, (ofNat (ℕ × Code) a.1.1.1.1.length).2), Nat.pair (unpair a.1.1.1.2).1 a.2).1
      (a.1.1.1.1, (a.1.1.2, (ofNat (ℕ × Code) a.1.1.1.1.length).2), Nat.pair (unpair a.1.1.1.2).1 a.2).2.1
      (a.1.1.1.1, (a.1.1.2, (ofNat (ℕ × Code) a.1.1.1.1.length).2), Nat.pair (unpair a.1.1.1.2).1 a.2).2.2
⊢ Primrec fun p =>
    (fun p i =>
        Nat.Partrec.Code.lup p.1.1.1.1 ((ofNat (ℕ × Code) p.1.1.1.1.length).1, p.1.2.2.1)
          (Nat.pair (unpair p.1.1.1.2).1 (Nat.pair p.2 i)))
      p.1 p.2

Tactic:
have z := z.comp (Primrec.fst (β := ℕ))

Result:
case hpc
a : Primrec fun a => ofNat (ℕ × Code) a.length
k✝¹ : Primrec fun a => (ofNat (ℕ × Code) a.1.length).1
n✝¹ : Primrec Prod.snd
k✝ : Primrec fun a => (ofNat (ℕ × Code) a.1.1.length).1
n✝ : Primrec fun a => a.1.2
k' : Primrec Prod.snd
c : Primrec fun a => (ofNat (ℕ × Code) a.1.1.length).2
L✝ : Primrec fun a => a.1.1.1
k : Primrec fun a => (ofNat (ℕ × Code) a.1.1.1.length).1
n : Primrec fun a => a.1.1.2
cf : Primrec fun a => a.2.1
cg : Primrec fun a => a.2.2.1
z✝¹ : Primrec fun a => (unpair a.1.1.2).1
L : Primrec fun a => a.1.1.1.1
z✝ : Primrec fun a => (unpair a.1.1.1.2).1
y : Primrec Prod.snd
h₁ :
  Primrec fun a =>
    Nat.Partrec.Code.lup
      (a.1.1.1.1, (a.1.1.2, (ofNat (ℕ × Code) a.1.1.1.1.length).2), Nat.pair (unpair a.1.1.1.2).1 a.2).1
      (a.1.1.1.1, (a.1.1.2, (ofNat (ℕ × Code) a.1.1.1.1.length).2), Nat.pair (unpair a.1.1.1.2).1 a.2).2.1
      (a.1.1.1.1, (a.1.1.2, (ofNat (ℕ × Code) a.1.1.1.1.length).2), Nat.pair (unpair a.1.1.1.2).1 a.2).2.2
z : Primrec fun a => (unpair a.1.1.1.1.2).1
⊢ Primrec fun p =>
    (fun p i =>
        Nat.Partrec.Code.lup p.1.1.1.1 ((ofNat (ℕ × Code) p.1.1.1.1.length).1, p.1.2.2.1)
          (Nat.pair (unpair p.1.1.1.2).1 (Nat.pair p.2 i)))
      p.1 p.2

Proof state:
a : Primrec fun a => ofNat (ℕ × Code) a.length
k : Primrec fun a => (ofNat (ℕ × Code) a.1.length).1
n : Primrec Prod.snd
⊢ Primrec fun p =>
    (fun a n =>
        Nat.casesOn (ofNat (ℕ × Code) a.length).1 Option.none fun k' =>
          Code.recOn (ofNat (ℕ × Code) a.length).2 (some 0) (some n.succ) (some (unpair n).1) (some (unpair n).2)
            (fun cf cg x x => do
              let x ← Nat.Partrec.Code.lup a ((ofNat (ℕ × Code) a.length).1, cf) n
              let y ← Nat.Partrec.Code.lup a ((ofNat (ℕ × Code) a.length).1, cg) n
              some (Nat.pair x y))
            (fun cf cg x x => do
              let x ← Nat.Partrec.Code.lup a ((ofNat (ℕ × Code) a.length).1, cg) n
              Nat.Partrec.Code.lup a ((ofNat (ℕ × Code) a.length).1, cf) x)
            (fun cf cg x x =>
              let z := (unpair n).1;
              Nat.casesOn (unpair n).2 (Nat.Partrec.Code.lup a ((ofNat (ℕ × Code) a.length).1, cf) z) fun y => do
                let i ← Nat.Partrec.Code.lup a (k', (ofNat (ℕ × Code) a.length).2) (Nat.pair z y)
                Nat.Partrec.Code.lup a ((ofNat (ℕ × Code) a.length).1, cg) (Nat.pair z (Nat.pair y i)))
            fun cf x =>
            let z := (unpair n).1;
            let m := (unpair n).2;
            do
            let x ← Nat.Partrec.Code.lup a ((ofNat (ℕ × Code) a.length).1, cf) (Nat.pair z m)
            Nat.casesOn x (some m) fun x =>
                Nat.Partrec.Code.lup a (k', (ofNat (ℕ × Code) a.length).2) (Nat.pair z (m + 1)))
      p.1 p.2

Tactic:
refine Primrec.nat_casesOn k (_root_.Primrec.const Option.none) (?_ : Primrec _)

Result:
a : Primrec fun a => ofNat (ℕ × Code) a.length
k : Primrec fun a => (ofNat (ℕ × Code) a.1.length).1
n : Primrec Prod.snd
⊢ Primrec fun p =>
    (fun p k' =>
        Code.recOn (ofNat (ℕ × Code) p.1.length).2 (some 0) (some p.2.succ) (some (unpair p.2).1) (some (unpair p.2).2)
          (fun cf cg x x => do
            let x ← Nat.Partrec.Code.lup p.1 ((ofNat (ℕ × Code) p.1.length).1, cf) p.2
            let y ← Nat.Partrec.Code.lup p.1 ((ofNat (ℕ × Code) p.1.length).1, cg) p.2
            some (Nat.pair x y))
          (fun cf cg x x => do
            let x ← Nat.Partrec.Code.lup p.1 ((ofNat (ℕ × Code) p.1.length).1, cg) p.2
            Nat.Partrec.Code.lup p.1 ((ofNat (ℕ × Code) p.1.length).1, cf) x)
          (fun cf cg x x =>
            let z := (unpair p.2).1;
            Nat.casesOn (unpair p.2).2 (Nat.Partrec.Code.lup p.1 ((ofNat (ℕ × Code) p.1.length).1, cf) z) fun y => do
              let i ← Nat.Partrec.Code.lup p.1 (k', (ofNat (ℕ × Code) p.1.length).2) (Nat.pair z y)
              Nat.Partrec.Code.lup p.1 ((ofNat (ℕ × Code) p.1.length).1, cg) (Nat.pair z (Nat.pair y i)))
          fun cf x =>
          let z := (unpair p.2).1;
          let m := (unpair p.2).2;
          do
          let x ← Nat.Partrec.Code.lup p.1 ((ofNat (ℕ × Code) p.1.length).1, cf) (Nat.pair z m)
          Nat.casesOn x (some m) fun x =>
              Nat.Partrec.Code.lup p.1 (k', (ofNat (ℕ × Code) p.1.length).2) (Nat.pair z (m + 1)))
      p.1 p.2