l3lab/ntp-mathlib huggingface dataset:
theorem fst {α β} [Primcodable α] [Primcodable β] : Primrec (@Prod.fst α β) :=
  ((casesOn' zero
            ((casesOn' zero (Nat.Primrec.succ.comp left)).comp
              (pair right ((@Primcodable.prim β).comp left)))).comp
        (pair right ((@Primcodable.prim α).comp left))).of_eq
    fun n => by
    

Proof state:
α✝ : Type u_1
σ : Type u_2
inst✝³ : Primcodable α✝
inst✝² : Primcodable σ
α : Type u_3
β : Type u_4
inst✝¹ : Primcodable α
inst✝ : Primcodable β
n : ℕ
⊢ Nat.unpaired
      (fun z n =>
        Nat.casesOn n 0 fun y =>
          Nat.unpaired (fun z n => Nat.casesOn n 0 fun y => Nat.succ (Nat.unpair (Nat.pair z y)).1)
            (Nat.pair (Nat.unpair (Nat.pair z y)).2 (encode (decode (Nat.unpair (Nat.pair z y)).1))))
      (Nat.pair (Nat.unpair n).2 (encode (decode (Nat.unpair n).1))) =
    encode (Option.map Prod.fst (decode n))

Next tactic:
simp only [Nat.unpaired, Nat.unpair_pair, decode_prod_val]
theorem fst {α β} [Primcodable α] [Primcodable β] : Primrec (@Prod.fst α β) :=
  ((casesOn' zero
            ((casesOn' zero (Nat.Primrec.succ.comp left)).comp
              (pair right ((@Primcodable.prim β).comp left)))).comp
        (pair right ((@Primcodable.prim α).comp left))).of_eq
    fun n => by
    simp only [Nat.unpaired, Nat.unpair_pair, decode_prod_val]
    

Proof state:
α✝ : Type u_1
σ : Type u_2
inst✝³ : Primcodable α✝
inst✝² : Primcodable σ
α : Type u_3
β : Type u_4
inst✝¹ : Primcodable α
inst✝ : Primcodable β
n : ℕ
⊢ Nat.rec 0 (fun n_1 n_ih => Nat.rec 0 (fun n n_ih => Nat.succ n_1) (encode (decode (Nat.unpair n).2)))
      (encode (decode (Nat.unpair n).1)) =
    encode
      (Option.map Prod.fst
        (Option.bind (decode (Nat.unpair n).1) fun a => Option.map (Prod.mk a) (decode (Nat.unpair n).2)))

Next tactic:
cases @decode α _ n.unpair.1
theorem fst {α β} [Primcodable α] [Primcodable β] : Primrec (@Prod.fst α β) :=
  ((casesOn' zero
            ((casesOn' zero (Nat.Primrec.succ.comp left)).comp
              (pair right ((@Primcodable.prim β).comp left)))).comp
        (pair right ((@Primcodable.prim α).comp left))).of_eq
    fun n => by
    simp only [Nat.unpaired, Nat.unpair_pair, decode_prod_val]
    cases @decode α _ n.unpair.1 <;> 

Proof state:
case none
α✝ : Type u_1
σ : Type u_2
inst✝³ : Primcodable α✝
inst✝² : Primcodable σ
α : Type u_3
β : Type u_4
inst✝¹ : Primcodable α
inst✝ : Primcodable β
n : ℕ
⊢ Nat.rec 0 (fun n_1 n_ih => Nat.rec 0 (fun n n_ih => Nat.succ n_1) (encode (decode (Nat.unpair n).2))) (encode none) =
    encode (Option.map Prod.fst (Option.bind none fun a => Option.map (Prod.mk a) (decode (Nat.unpair n).2)))

Next tactic:
simp
theorem fst {α β} [Primcodable α] [Primcodable β] : Primrec (@Prod.fst α β) :=
  ((casesOn' zero
            ((casesOn' zero (Nat.Primrec.succ.comp left)).comp
              (pair right ((@Primcodable.prim β).comp left)))).comp
        (pair right ((@Primcodable.prim α).comp left))).of_eq
    fun n => by
    simp only [Nat.unpaired, Nat.unpair_pair, decode_prod_val]
    cases @decode α _ n.unpair.1 <;> 

Proof state:
case some
α✝ : Type u_1
σ : Type u_2
inst✝³ : Primcodable α✝
inst✝² : Primcodable σ
α : Type u_3
β : Type u_4
inst✝¹ : Primcodable α
inst✝ : Primcodable β
n : ℕ
val✝ : α
⊢ Nat.rec 0 (fun n_1 n_ih => Nat.rec 0 (fun n n_ih => Nat.succ n_1) (encode (decode (Nat.unpair n).2)))
      (encode (some val✝)) =
    encode (Option.map Prod.fst (Option.bind (some val✝) fun a => Option.map (Prod.mk a) (decode (Nat.unpair n).2)))

Next tactic:
simp
theorem fst {α β} [Primcodable α] [Primcodable β] : Primrec (@Prod.fst α β) :=
  ((casesOn' zero
            ((casesOn' zero (Nat.Primrec.succ.comp left)).comp
              (pair right ((@Primcodable.prim β).comp left)))).comp
        (pair right ((@Primcodable.prim α).comp left))).of_eq
    fun n => by
    simp only [Nat.unpaired, Nat.unpair_pair, decode_prod_val]
    cases @decode α _ n.unpair.1 <;> simp
    

Proof state:
case some
α✝ : Type u_1
σ : Type u_2
inst✝³ : Primcodable α✝
inst✝² : Primcodable σ
α : Type u_3
β : Type u_4
inst✝¹ : Primcodable α
inst✝ : Primcodable β
n : ℕ
val✝ : α
⊢ Nat.rec 0 (fun n n_ih => Nat.succ (encode val✝)) (encode (decode (Nat.unpair n).2)) =
    encode (Option.map (Function.const β val✝) (decode (Nat.unpair n).2))

Next tactic:
cases @decode β _ n.unpair.2
theorem fst {α β} [Primcodable α] [Primcodable β] : Primrec (@Prod.fst α β) :=
  ((casesOn' zero
            ((casesOn' zero (Nat.Primrec.succ.comp left)).comp
              (pair right ((@Primcodable.prim β).comp left)))).comp
        (pair right ((@Primcodable.prim α).comp left))).of_eq
    fun n => by
    simp only [Nat.unpaired, Nat.unpair_pair, decode_prod_val]
    cases @decode α _ n.unpair.1 <;> simp
    cases @decode β _ n.unpair.2 <;> 

Proof state:
case some.none
α✝ : Type u_1
σ : Type u_2
inst✝³ : Primcodable α✝
inst✝² : Primcodable σ
α : Type u_3
β : Type u_4
inst✝¹ : Primcodable α
inst✝ : Primcodable β
n : ℕ
val✝ : α
⊢ Nat.rec 0 (fun n n_ih => Nat.succ (encode val✝)) (encode none) = encode (Option.map (Function.const β val✝) none)

Next tactic:
simp
theorem fst {α β} [Primcodable α] [Primcodable β] : Primrec (@Prod.fst α β) :=
  ((casesOn' zero
            ((casesOn' zero (Nat.Primrec.succ.comp left)).comp
              (pair right ((@Primcodable.prim β).comp left)))).comp
        (pair right ((@Primcodable.prim α).comp left))).of_eq
    fun n => by
    simp only [Nat.unpaired, Nat.unpair_pair, decode_prod_val]
    cases @decode α _ n.unpair.1 <;> simp
    cases @decode β _ n.unpair.2 <;> 

Proof state:
case some.some
α✝ : Type u_1
σ : Type u_2
inst✝³ : Primcodable α✝
inst✝² : Primcodable σ
α : Type u_3
β : Type u_4
inst✝¹ : Primcodable α
inst✝ : Primcodable β
n : ℕ
val✝¹ : α
val✝ : β
⊢ Nat.rec 0 (fun n n_ih => Nat.succ (encode val✝¹)) (encode (some val✝)) =
    encode (Option.map (Function.const β val✝¹) (some val✝))

Next tactic:
simp
theorem snd {α β} [Primcodable α] [Primcodable β] : Primrec (@Prod.snd α β) :=
  ((casesOn' zero
            ((casesOn' zero (Nat.Primrec.succ.comp right)).comp
              (pair right ((@Primcodable.prim β).comp left)))).comp
        (pair right ((@Primcodable.prim α).comp left))).of_eq
    fun n => by
    

Proof state:
α✝ : Type u_1
σ : Type u_2
inst✝³ : Primcodable α✝
inst✝² : Primcodable σ
α : Type u_3
β : Type u_4
inst✝¹ : Primcodable α
inst✝ : Primcodable β
n : ℕ
⊢ Nat.unpaired
      (fun z n =>
        Nat.casesOn n 0 fun y =>
          Nat.unpaired (fun z n => Nat.casesOn n 0 fun y => Nat.succ (Nat.unpair (Nat.pair z y)).2)
            (Nat.pair (Nat.unpair (Nat.pair z y)).2 (encode (decode (Nat.unpair (Nat.pair z y)).1))))
      (Nat.pair (Nat.unpair n).2 (encode (decode (Nat.unpair n).1))) =
    encode (Option.map Prod.snd (decode n))

Next tactic:
simp only [Nat.unpaired, Nat.unpair_pair, decode_prod_val]
theorem snd {α β} [Primcodable α] [Primcodable β] : Primrec (@Prod.snd α β) :=
  ((casesOn' zero
            ((casesOn' zero (Nat.Primrec.succ.comp right)).comp
              (pair right ((@Primcodable.prim β).comp left)))).comp
        (pair right ((@Primcodable.prim α).comp left))).of_eq
    fun n => by
    simp only [Nat.unpaired, Nat.unpair_pair, decode_prod_val]
    

Proof state:
α✝ : Type u_1
σ : Type u_2
inst✝³ : Primcodable α✝
inst✝² : Primcodable σ
α : Type u_3
β : Type u_4
inst✝¹ : Primcodable α
inst✝ : Primcodable β
n : ℕ
⊢ Nat.rec 0 (fun n_1 n_ih => Nat.rec 0 (fun n n_ih => Nat.succ n) (encode (decode (Nat.unpair n).2)))
      (encode (decode (Nat.unpair n).1)) =
    encode
      (Option.map Prod.snd
        (Option.bind (decode (Nat.unpair n).1) fun a => Option.map (Prod.mk a) (decode (Nat.unpair n).2)))

Next tactic:
cases @decode α _ n.unpair.1
theorem snd {α β} [Primcodable α] [Primcodable β] : Primrec (@Prod.snd α β) :=
  ((casesOn' zero
            ((casesOn' zero (Nat.Primrec.succ.comp right)).comp
              (pair right ((@Primcodable.prim β).comp left)))).comp
        (pair right ((@Primcodable.prim α).comp left))).of_eq
    fun n => by
    simp only [Nat.unpaired, Nat.unpair_pair, decode_prod_val]
    cases @decode α _ n.unpair.1 <;> 

Proof state:
case none
α✝ : Type u_1
σ : Type u_2
inst✝³ : Primcodable α✝
inst✝² : Primcodable σ
α : Type u_3
β : Type u_4
inst✝¹ : Primcodable α
inst✝ : Primcodable β
n : ℕ
⊢ Nat.rec 0 (fun n_1 n_ih => Nat.rec 0 (fun n n_ih => Nat.succ n) (encode (decode (Nat.unpair n).2))) (encode none) =
    encode (Option.map Prod.snd (Option.bind none fun a => Option.map (Prod.mk a) (decode (Nat.unpair n).2)))

Next tactic:
simp
theorem snd {α β} [Primcodable α] [Primcodable β] : Primrec (@Prod.snd α β) :=
  ((casesOn' zero
            ((casesOn' zero (Nat.Primrec.succ.comp right)).comp
              (pair right ((@Primcodable.prim β).comp left)))).comp
        (pair right ((@Primcodable.prim α).comp left))).of_eq
    fun n => by
    simp only [Nat.unpaired, Nat.unpair_pair, decode_prod_val]
    cases @decode α _ n.unpair.1 <;> 

Proof state:
case some
α✝ : Type u_1
σ : Type u_2
inst✝³ : Primcodable α✝
inst✝² : Primcodable σ
α : Type u_3
β : Type u_4
inst✝¹ : Primcodable α
inst✝ : Primcodable β
n : ℕ
val✝ : α
⊢ Nat.rec 0 (fun n_1 n_ih => Nat.rec 0 (fun n n_ih => Nat.succ n) (encode (decode (Nat.unpair n).2)))
      (encode (some val✝)) =
    encode (Option.map Prod.snd (Option.bind (some val✝) fun a => Option.map (Prod.mk a) (decode (Nat.unpair n).2)))

Next tactic:
simp
theorem snd {α β} [Primcodable α] [Primcodable β] : Primrec (@Prod.snd α β) :=
  ((casesOn' zero
            ((casesOn' zero (Nat.Primrec.succ.comp right)).comp
              (pair right ((@Primcodable.prim β).comp left)))).comp
        (pair right ((@Primcodable.prim α).comp left))).of_eq
    fun n => by
    simp only [Nat.unpaired, Nat.unpair_pair, decode_prod_val]
    cases @decode α _ n.unpair.1 <;> simp
    

Proof state:
case some
α✝ : Type u_1
σ : Type u_2
inst✝³ : Primcodable α✝
inst✝² : Primcodable σ
α : Type u_3
β : Type u_4
inst✝¹ : Primcodable α
inst✝ : Primcodable β
n : ℕ
val✝ : α
⊢ Nat.rec 0 (fun n n_ih => Nat.succ n) (encode (decode (Nat.unpair n).2)) = encode (decode (Nat.unpair n).2)

Next tactic:
cases @decode β _ n.unpair.2
theorem snd {α β} [Primcodable α] [Primcodable β] : Primrec (@Prod.snd α β) :=
  ((casesOn' zero
            ((casesOn' zero (Nat.Primrec.succ.comp right)).comp
              (pair right ((@Primcodable.prim β).comp left)))).comp
        (pair right ((@Primcodable.prim α).comp left))).of_eq
    fun n => by
    simp only [Nat.unpaired, Nat.unpair_pair, decode_prod_val]
    cases @decode α _ n.unpair.1 <;> simp
    cases @decode β _ n.unpair.2 <;> 

Proof state:
case some.none
α✝ : Type u_1
σ : Type u_2
inst✝³ : Primcodable α✝
inst✝² : Primcodable σ
α : Type u_3
β : Type u_4
inst✝¹ : Primcodable α
inst✝ : Primcodable β
n : ℕ
val✝ : α
⊢ Nat.rec 0 (fun n n_ih => Nat.succ n) (encode none) = encode none

Next tactic:
simp
theorem snd {α β} [Primcodable α] [Primcodable β] : Primrec (@Prod.snd α β) :=
  ((casesOn' zero
            ((casesOn' zero (Nat.Primrec.succ.comp right)).comp
              (pair right ((@Primcodable.prim β).comp left)))).comp
        (pair right ((@Primcodable.prim α).comp left))).of_eq
    fun n => by
    simp only [Nat.unpaired, Nat.unpair_pair, decode_prod_val]
    cases @decode α _ n.unpair.1 <;> simp
    cases @decode β _ n.unpair.2 <;> 

Proof state:
case some.some
α✝ : Type u_1
σ : Type u_2
inst✝³ : Primcodable α✝
inst✝² : Primcodable σ
α : Type u_3
β : Type u_4
inst✝¹ : Primcodable α
inst✝ : Primcodable β
n : ℕ
val✝¹ : α
val✝ : β
⊢ Nat.rec 0 (fun n n_ih => Nat.succ n) (encode (some val✝)) = encode (some val✝)

Next tactic:
simp
theorem pair {α β γ} [Primcodable α] [Primcodable β] [Primcodable γ] {f : α → β} {g : α → γ}
    (hf : Primrec f) (hg : Primrec g) : Primrec fun a => (f a, g a) :=
  ((casesOn1 0
            (Nat.Primrec.succ.comp <|
              .pair (Nat.Primrec.pred.comp hf) (Nat.Primrec.pred.comp hg))).comp
        (@Primcodable.prim α _)).of_eq
    fun n => by 

Proof state:
α✝ : Type u_1
σ : Type u_2
inst✝⁴ : Primcodable α✝
inst✝³ : Primcodable σ
α : Type u_3
β : Type u_4
γ : Type u_5
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable γ
f : α → β
g : α → γ
hf : Primrec f
hg : Primrec g
n : ℕ
⊢ (Nat.casesOn (encode (decode n)) 0 fun n =>
      Nat.succ (Nat.pair (Nat.pred (encode (Option.map f (decode n)))) (Nat.pred (encode (Option.map g (decode n)))))) =
    encode (Option.map (fun a => (f a, g a)) (decode n))

Next tactic:
cases @decode α _ n
theorem pair {α β γ} [Primcodable α] [Primcodable β] [Primcodable γ] {f : α → β} {g : α → γ}
    (hf : Primrec f) (hg : Primrec g) : Primrec fun a => (f a, g a) :=
  ((casesOn1 0
            (Nat.Primrec.succ.comp <|
              .pair (Nat.Primrec.pred.comp hf) (Nat.Primrec.pred.comp hg))).comp
        (@Primcodable.prim α _)).of_eq
    fun n => by cases @decode α _ n <;> 

Proof state:
case none
α✝ : Type u_1
σ : Type u_2
inst✝⁴ : Primcodable α✝
inst✝³ : Primcodable σ
α : Type u_3
β : Type u_4
γ : Type u_5
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable γ
f : α → β
g : α → γ
hf : Primrec f
hg : Primrec g
n : ℕ
⊢ (Nat.casesOn (encode none) 0 fun n =>
      Nat.succ (Nat.pair (Nat.pred (encode (Option.map f (decode n)))) (Nat.pred (encode (Option.map g (decode n)))))) =
    encode (Option.map (fun a => (f a, g a)) none)

Next tactic:
simp [encodek]
theorem pair {α β γ} [Primcodable α] [Primcodable β] [Primcodable γ] {f : α → β} {g : α → γ}
    (hf : Primrec f) (hg : Primrec g) : Primrec fun a => (f a, g a) :=
  ((casesOn1 0
            (Nat.Primrec.succ.comp <|
              .pair (Nat.Primrec.pred.comp hf) (Nat.Primrec.pred.comp hg))).comp
        (@Primcodable.prim α _)).of_eq
    fun n => by cases @decode α _ n <;> 

Proof state:
case some
α✝ : Type u_1
σ : Type u_2
inst✝⁴ : Primcodable α✝
inst✝³ : Primcodable σ
α : Type u_3
β : Type u_4
γ : Type u_5
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable γ
f : α → β
g : α → γ
hf : Primrec f
hg : Primrec g
n : ℕ
val✝ : α
⊢ (Nat.casesOn (encode (some val✝)) 0 fun n =>
      Nat.succ (Nat.pair (Nat.pred (encode (Option.map f (decode n)))) (Nat.pred (encode (Option.map g (decode n)))))) =
    encode (Option.map (fun a => (f a, g a)) (some val✝))

Next tactic:
simp [encodek]
theorem unpair : Primrec Nat.unpair :=
  (pair (nat_iff.2 .left) (nat_iff.2 .right)).of_eq fun n => by 

Proof state:
α : Type u_1
σ : Type u_2
inst✝¹ : Primcodable α
inst✝ : Primcodable σ
n : ℕ
⊢ ((Nat.unpair n).1, (Nat.unpair n).2) = Nat.unpair n

Next tactic:
simp
theorem list_get?₁ : ∀ l : List α, Primrec l.get?
  | [] => dom_denumerable.2 zero
  | a :: l =>
    dom_denumerable.2 <|
      (casesOn1 (encode a).succ <| dom_denumerable.1 <| list_get?₁ l).of_eq fun n => by
        

Proof state:
α : Type u_1
σ : Type u_2
inst✝¹ : Primcodable α
inst✝ : Primcodable σ
a : α
l : List α
n : ℕ
⊢ (Nat.casesOn n (Nat.succ (encode a)) fun n => encode (List.get? l (ofNat ℕ n))) =
    encode (List.get? (a :: l) (ofNat ℕ n))

Next tactic:
cases n
theorem list_get?₁ : ∀ l : List α, Primrec l.get?
  | [] => dom_denumerable.2 zero
  | a :: l =>
    dom_denumerable.2 <|
      (casesOn1 (encode a).succ <| dom_denumerable.1 <| list_get?₁ l).of_eq fun n => by
        cases n <;> 

Proof state:
case zero
α : Type u_1
σ : Type u_2
inst✝¹ : Primcodable α
inst✝ : Primcodable σ
a : α
l : List α
⊢ (Nat.casesOn Nat.zero (Nat.succ (encode a)) fun n => encode (List.get? l (ofNat ℕ n))) =
    encode (List.get? (a :: l) (ofNat ℕ Nat.zero))

Next tactic:
simp
theorem list_get?₁ : ∀ l : List α, Primrec l.get?
  | [] => dom_denumerable.2 zero
  | a :: l =>
    dom_denumerable.2 <|
      (casesOn1 (encode a).succ <| dom_denumerable.1 <| list_get?₁ l).of_eq fun n => by
        cases n <;> 

Proof state:
case succ
α : Type u_1
σ : Type u_2
inst✝¹ : Primcodable α
inst✝ : Primcodable σ
a : α
l : List α
n✝ : ℕ
⊢ (Nat.casesOn (Nat.succ n✝) (Nat.succ (encode a)) fun n => encode (List.get? l (ofNat ℕ n))) =
    encode (List.get? (a :: l) (ofNat ℕ (Nat.succ n✝)))

Next tactic:
simp
theorem of_eq {f g : α → β → σ} (hg : Primrec₂ f) (H : ∀ a b, f a b = g a b) : Primrec₂ g :=
  (by 

Proof state:
α : Type u_1
β : Type u_2
σ : Type u_3
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable σ
f g : α → β → σ
hg : Primrec₂ f
H : ∀ (a : α) (b : β), f a b = g a b
⊢ f = g

Next tactic:
funext a b
theorem of_eq {f g : α → β → σ} (hg : Primrec₂ f) (H : ∀ a b, f a b = g a b) : Primrec₂ g :=
  (by funext a b; 

Proof state:
case h.h
α : Type u_1
β : Type u_2
σ : Type u_3
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable σ
f g : α → β → σ
hg : Primrec₂ f
H : ∀ (a : α) (b : β), f a b = g a b
a : α
b : β
⊢ f a b = g a b

Next tactic:
apply H
theorem natPair : Primrec₂ Nat.pair := by 

Proof state:
α : Type u_1
β : Type u_2
σ : Type u_3
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable σ
⊢ Primrec₂ Nat.pair

Next tactic:
simp [Primrec₂, Primrec]
theorem natPair : Primrec₂ Nat.pair := by simp [Primrec₂, Primrec]; 

Proof state:
α : Type u_1
β : Type u_2
σ : Type u_3
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable σ
⊢ Nat.Primrec fun n => Nat.succ n

Next tactic:
constructor
theorem unpaired {f : ℕ → ℕ → α} : Primrec (Nat.unpaired f) ↔ Primrec₂ f :=
  ⟨fun h => by 

Proof state:
α : Type u_1
β : Type u_2
σ : Type u_3
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable σ
f : ℕ → ℕ → α
h : Primrec (Nat.unpaired f)
⊢ Primrec₂ f

Next tactic:
simpa using h.comp natPair
theorem ofNat_iff {α β σ} [Denumerable α] [Denumerable β] [Primcodable σ] {f : α → β → σ} :
    Primrec₂ f ↔ Primrec₂ fun m n : ℕ => f (ofNat α m) (ofNat β n) :=
  (Primrec.ofNat_iff.trans <| by 

Proof state:
α✝ : Type u_1
β✝ : Type u_2
σ✝ : Type u_3
inst✝⁵ : Primcodable α✝
inst✝⁴ : Primcodable β✝
inst✝³ : Primcodable σ✝
α : Type u_4
β : Type u_5
σ : Type u_6
inst✝² : Denumerable α
inst✝¹ : Denumerable β
inst✝ : Primcodable σ
f : α → β → σ
⊢ (Primrec fun n => f (ofNat (α × β) n).1 (ofNat (α × β) n).2) ↔
    Primrec (Nat.unpaired fun m n => f (ofNat α m) (ofNat β n))

Next tactic:
simp
theorem uncurry {f : α → β → σ} : Primrec (Function.uncurry f) ↔ Primrec₂ f := by
  

Proof state:
α : Type u_1
β : Type u_2
σ : Type u_3
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable σ
f : α → β → σ
⊢ Primrec (Function.uncurry f) ↔ Primrec₂ f

Next tactic:
rw [show Function.uncurry f = fun p : α × β => f p.1 p.2 from funext fun ⟨a, b⟩ => rfl]
theorem uncurry {f : α → β → σ} : Primrec (Function.uncurry f) ↔ Primrec₂ f := by
  rw [show Function.uncurry f = fun p : α × β => f p.1 p.2 from funext fun ⟨a, b⟩ => rfl]; 

Proof state:
α : Type u_1
β : Type u_2
σ : Type u_3
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable σ
f : α → β → σ
⊢ (Primrec fun p => f p.1 p.2) ↔ Primrec₂ f

Next tactic:
rfl
theorem curry {f : α × β → σ} : Primrec₂ (Function.curry f) ↔ Primrec f := by
  

Proof state:
α : Type u_1
β : Type u_2
σ : Type u_3
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable σ
f : α × β → σ
⊢ Primrec₂ (Function.curry f) ↔ Primrec f

Next tactic:
rw [← uncurry, Function.uncurry_curry]
theorem nat_iff {f : α → β → σ} : Primrec₂ f ↔ Nat.Primrec
    (.unpaired fun m n => encode <| (@decode α _ m).bind fun a => (@decode β _ n).map (f a)) := by
  

Proof state:
α : Type u_1
β : Type u_2
σ : Type u_3
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable σ
f : α → β → σ
⊢ Primrec₂ f ↔
    Nat.Primrec (Nat.unpaired fun m n => encode (Option.bind (decode m) fun a => Option.map (f a) (decode n)))

Next tactic:
have :
    ∀ (a : Option α) (b : Option β),
      Option.map (fun p : α × β => f p.1 p.2)
          (Option.bind a fun a : α => Option.map (Prod.mk a) b) =
        Option.bind a fun a => Option.map (f a) b := fun a b => by
          cases a <;> cases b <;> rfl
theorem nat_iff {f : α → β → σ} : Primrec₂ f ↔ Nat.Primrec
    (.unpaired fun m n => encode <| (@decode α _ m).bind fun a => (@decode β _ n).map (f a)) := by
  have :
    ∀ (a : Option α) (b : Option β),
      Option.map (fun p : α × β => f p.1 p.2)
          (Option.bind a fun a : α => Option.map (Prod.mk a) b) =
        Option.bind a fun a => Option.map (f a) b := fun a b => by
          

Proof state:
α : Type u_1
β : Type u_2
σ : Type u_3
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable σ
f : α → β → σ
a : Option α
b : Option β
⊢ Option.map (fun p => f p.1 p.2) (Option.bind a fun a => Option.map (Prod.mk a) b) =
    Option.bind a fun a => Option.map (f a) b

Next tactic:
cases a
theorem nat_iff {f : α → β → σ} : Primrec₂ f ↔ Nat.Primrec
    (.unpaired fun m n => encode <| (@decode α _ m).bind fun a => (@decode β _ n).map (f a)) := by
  have :
    ∀ (a : Option α) (b : Option β),
      Option.map (fun p : α × β => f p.1 p.2)
          (Option.bind a fun a : α => Option.map (Prod.mk a) b) =
        Option.bind a fun a => Option.map (f a) b := fun a b => by
          cases a <;> 

Proof state:
case none
α : Type u_1
β : Type u_2
σ : Type u_3
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable σ
f : α → β → σ
b : Option β
⊢ Option.map (fun p => f p.1 p.2) (Option.bind none fun a => Option.map (Prod.mk a) b) =
    Option.bind none fun a => Option.map (f a) b

Next tactic:
cases b
theorem nat_iff {f : α → β → σ} : Primrec₂ f ↔ Nat.Primrec
    (.unpaired fun m n => encode <| (@decode α _ m).bind fun a => (@decode β _ n).map (f a)) := by
  have :
    ∀ (a : Option α) (b : Option β),
      Option.map (fun p : α × β => f p.1 p.2)
          (Option.bind a fun a : α => Option.map (Prod.mk a) b) =
        Option.bind a fun a => Option.map (f a) b := fun a b => by
          cases a <;> 

Proof state:
case some
α : Type u_1
β : Type u_2
σ : Type u_3
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable σ
f : α → β → σ
b : Option β
val✝ : α
⊢ Option.map (fun p => f p.1 p.2) (Option.bind (some val✝) fun a => Option.map (Prod.mk a) b) =
    Option.bind (some val✝) fun a => Option.map (f a) b

Next tactic:
cases b
theorem nat_iff {f : α → β → σ} : Primrec₂ f ↔ Nat.Primrec
    (.unpaired fun m n => encode <| (@decode α _ m).bind fun a => (@decode β _ n).map (f a)) := by
  have :
    ∀ (a : Option α) (b : Option β),
      Option.map (fun p : α × β => f p.1 p.2)
          (Option.bind a fun a : α => Option.map (Prod.mk a) b) =
        Option.bind a fun a => Option.map (f a) b := fun a b => by
          cases a <;> cases b <;> 

Proof state:
case none.none
α : Type u_1
β : Type u_2
σ : Type u_3
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable σ
f : α → β → σ
⊢ Option.map (fun p => f p.1 p.2) (Option.bind none fun a => Option.map (Prod.mk a) none) =
    Option.bind none fun a => Option.map (f a) none

Next tactic:
rfl
theorem nat_iff {f : α → β → σ} : Primrec₂ f ↔ Nat.Primrec
    (.unpaired fun m n => encode <| (@decode α _ m).bind fun a => (@decode β _ n).map (f a)) := by
  have :
    ∀ (a : Option α) (b : Option β),
      Option.map (fun p : α × β => f p.1 p.2)
          (Option.bind a fun a : α => Option.map (Prod.mk a) b) =
        Option.bind a fun a => Option.map (f a) b := fun a b => by
          cases a <;> cases b <;> 

Proof state:
case none.some
α : Type u_1
β : Type u_2
σ : Type u_3
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable σ
f : α → β → σ
val✝ : β
⊢ Option.map (fun p => f p.1 p.2) (Option.bind none fun a => Option.map (Prod.mk a) (some val✝)) =
    Option.bind none fun a => Option.map (f a) (some val✝)

Next tactic:
rfl
theorem nat_iff {f : α → β → σ} : Primrec₂ f ↔ Nat.Primrec
    (.unpaired fun m n => encode <| (@decode α _ m).bind fun a => (@decode β _ n).map (f a)) := by
  have :
    ∀ (a : Option α) (b : Option β),
      Option.map (fun p : α × β => f p.1 p.2)
          (Option.bind a fun a : α => Option.map (Prod.mk a) b) =
        Option.bind a fun a => Option.map (f a) b := fun a b => by
          cases a <;> cases b <;> 

Proof state:
case some.none
α : Type u_1
β : Type u_2
σ : Type u_3
inst✝² : Primcodable α
inst✝¹ : Primcodable β
inst✝ : Primcodable σ
f : α → β → σ
val✝ : α
⊢ Option.map (fun p => f p.1 p.2) (Option.bind (some val✝) fun a => Option.map (Prod.mk a) none) =
    Option.bind (some val✝) fun a => Option.map (f a) none

Next tactic:
rfl