l3lab/ntp-mathlib huggingface dataset:
/-- A subtype of a primitive recursive predicate is `Primcodable`. -/
def subtype {p : α → Prop} [DecidablePred p] (hp : PrimrecPred p) : Primcodable (Subtype p) :=
  ⟨have : Primrec fun n => (@decode α _ n).bind fun a => Option.guard p a :=
    option_bind .decode (option_guard (hp.comp snd).to₂ snd)
  nat_iff.1 <| (encode_iff.2 this).of_eq fun n =>
    show _ = encode ((@decode α _ n).bind fun a => _) by
      cases' @decode α _ n with a; · rfl
      dsimp [Option.guard]
      by_cases h : p a <;> 

Proof state:
case pos
α : Type u_1
β : Type u_2
inst✝² : Primcodable α
inst✝¹ : Primcodable β
p : α → Prop
inst✝ : DecidablePred p
hp : PrimrecPred p
this : Primrec fun n => Option.bind (decode n) fun a => Option.guard p a
n : ℕ
a : α
h : p a
⊢ encode (if p a then some a else none) = encode (if h : p a then some { val := a, property := h } else none)

Next tactic:
simp [h]
/-- A subtype of a primitive recursive predicate is `Primcodable`. -/
def subtype {p : α → Prop} [DecidablePred p] (hp : PrimrecPred p) : Primcodable (Subtype p) :=
  ⟨have : Primrec fun n => (@decode α _ n).bind fun a => Option.guard p a :=
    option_bind .decode (option_guard (hp.comp snd).to₂ snd)
  nat_iff.1 <| (encode_iff.2 this).of_eq fun n =>
    show _ = encode ((@decode α _ n).bind fun a => _) by
      cases' @decode α _ n with a; · rfl
      dsimp [Option.guard]
      by_cases h : p a <;> 

Proof state:
case neg
α : Type u_1
β : Type u_2
inst✝² : Primcodable α
inst✝¹ : Primcodable β
p : α → Prop
inst✝ : DecidablePred p
hp : PrimrecPred p
this : Primrec fun n => Option.bind (decode n) fun a => Option.guard p a
n : ℕ
a : α
h : ¬p a
⊢ encode (if p a then some a else none) = encode (if h : p a then some { val := a, property := h } else none)

Next tactic:
simp [h]
/-- A subtype of a primitive recursive predicate is `Primcodable`. -/
def subtype {p : α → Prop} [DecidablePred p] (hp : PrimrecPred p) : Primcodable (Subtype p) :=
  ⟨have : Primrec fun n => (@decode α _ n).bind fun a => Option.guard p a :=
    option_bind .decode (option_guard (hp.comp snd).to₂ snd)
  nat_iff.1 <| (encode_iff.2 this).of_eq fun n =>
    show _ = encode ((@decode α _ n).bind fun a => _) by
      cases' @decode α _ n with a; · rfl
      dsimp [Option.guard]
      by_cases h : p a <;> simp [h]; 

Proof state:
case pos
α : Type u_1
β : Type u_2
inst✝² : Primcodable α
inst✝¹ : Primcodable β
p : α → Prop
inst✝ : DecidablePred p
hp : PrimrecPred p
this : Primrec fun n => Option.bind (decode n) fun a => Option.guard p a
n : ℕ
a : α
h : p a
⊢ encode a = encode { val := a, property := (_ : p a) }

Next tactic:
rfl
theorem subtype_val {p : α → Prop} [DecidablePred p] {hp : PrimrecPred p} :
    haveI := Primcodable.subtype hp
    Primrec (@Subtype.val α p) := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝⁴ : Primcodable α
inst✝³ : Primcodable β
inst✝² : Primcodable γ
inst✝¹ : Primcodable σ
p : α → Prop
inst✝ : DecidablePred p
hp : PrimrecPred p
⊢ Primrec Subtype.val

Next tactic:
letI := Primcodable.subtype hp
theorem subtype_val {p : α → Prop} [DecidablePred p] {hp : PrimrecPred p} :
    haveI := Primcodable.subtype hp
    Primrec (@Subtype.val α p) := by
  letI := Primcodable.subtype hp
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝⁴ : Primcodable α
inst✝³ : Primcodable β
inst✝² : Primcodable γ
inst✝¹ : Primcodable σ
p : α → Prop
inst✝ : DecidablePred p
hp : PrimrecPred p
this : Primcodable (Subtype p) := Primcodable.subtype hp
⊢ Primrec Subtype.val

Next tactic:
refine' (@Primcodable.prim (Subtype p)).of_eq fun n => _
theorem subtype_val {p : α → Prop} [DecidablePred p] {hp : PrimrecPred p} :
    haveI := Primcodable.subtype hp
    Primrec (@Subtype.val α p) := by
  letI := Primcodable.subtype hp
  refine' (@Primcodable.prim (Subtype p)).of_eq fun n => _
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝⁴ : Primcodable α
inst✝³ : Primcodable β
inst✝² : Primcodable γ
inst✝¹ : Primcodable σ
p : α → Prop
inst✝ : DecidablePred p
hp : PrimrecPred p
this : Primcodable (Subtype p) := Primcodable.subtype hp
n : ℕ
⊢ encode (decode n) = encode (Option.map Subtype.val (decode n))

Next tactic:
rcases @decode (Subtype p) _ n with (_ | ⟨a, h⟩)
theorem subtype_val {p : α → Prop} [DecidablePred p] {hp : PrimrecPred p} :
    haveI := Primcodable.subtype hp
    Primrec (@Subtype.val α p) := by
  letI := Primcodable.subtype hp
  refine' (@Primcodable.prim (Subtype p)).of_eq fun n => _
  rcases @decode (Subtype p) _ n with (_ | ⟨a, h⟩) <;> 

Proof state:
case none
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝⁴ : Primcodable α
inst✝³ : Primcodable β
inst✝² : Primcodable γ
inst✝¹ : Primcodable σ
p : α → Prop
inst✝ : DecidablePred p
hp : PrimrecPred p
this : Primcodable (Subtype p) := Primcodable.subtype hp
n : ℕ
⊢ encode none = encode (Option.map Subtype.val none)

Next tactic:
rfl
theorem subtype_val {p : α → Prop} [DecidablePred p] {hp : PrimrecPred p} :
    haveI := Primcodable.subtype hp
    Primrec (@Subtype.val α p) := by
  letI := Primcodable.subtype hp
  refine' (@Primcodable.prim (Subtype p)).of_eq fun n => _
  rcases @decode (Subtype p) _ n with (_ | ⟨a, h⟩) <;> 

Proof state:
case some.mk
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝⁴ : Primcodable α
inst✝³ : Primcodable β
inst✝² : Primcodable γ
inst✝¹ : Primcodable σ
p : α → Prop
inst✝ : DecidablePred p
hp : PrimrecPred p
this : Primcodable (Subtype p) := Primcodable.subtype hp
n : ℕ
a : α
h : p a
⊢ encode (some { val := a, property := h }) = encode (Option.map Subtype.val (some { val := a, property := h }))

Next tactic:
rfl
theorem subtype_val_iff {p : β → Prop} [DecidablePred p] {hp : PrimrecPred p} {f : α → Subtype p} :
    haveI := Primcodable.subtype hp
    (Primrec fun a => (f a).1) ↔ Primrec f := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝⁴ : Primcodable α
inst✝³ : Primcodable β
inst✝² : Primcodable γ
inst✝¹ : Primcodable σ
p : β → Prop
inst✝ : DecidablePred p
hp : PrimrecPred p
f : α → Subtype p
⊢ (Primrec fun a => ↑(f a)) ↔ Primrec f

Next tactic:
letI := Primcodable.subtype hp
theorem subtype_val_iff {p : β → Prop} [DecidablePred p] {hp : PrimrecPred p} {f : α → Subtype p} :
    haveI := Primcodable.subtype hp
    (Primrec fun a => (f a).1) ↔ Primrec f := by
  letI := Primcodable.subtype hp
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝⁴ : Primcodable α
inst✝³ : Primcodable β
inst✝² : Primcodable γ
inst✝¹ : Primcodable σ
p : β → Prop
inst✝ : DecidablePred p
hp : PrimrecPred p
f : α → Subtype p
this : Primcodable (Subtype p) := Primcodable.subtype hp
⊢ (Primrec fun a => ↑(f a)) ↔ Primrec f

Next tactic:
refine' ⟨fun h => _, fun hf => subtype_val.comp hf⟩
theorem subtype_val_iff {p : β → Prop} [DecidablePred p] {hp : PrimrecPred p} {f : α → Subtype p} :
    haveI := Primcodable.subtype hp
    (Primrec fun a => (f a).1) ↔ Primrec f := by
  letI := Primcodable.subtype hp
  refine' ⟨fun h => _, fun hf => subtype_val.comp hf⟩
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝⁴ : Primcodable α
inst✝³ : Primcodable β
inst✝² : Primcodable γ
inst✝¹ : Primcodable σ
p : β → Prop
inst✝ : DecidablePred p
hp : PrimrecPred p
f : α → Subtype p
this : Primcodable (Subtype p) := Primcodable.subtype hp
h : Primrec fun a => ↑(f a)
⊢ Primrec f

Next tactic:
refine' Nat.Primrec.of_eq h fun n => _
theorem subtype_val_iff {p : β → Prop} [DecidablePred p] {hp : PrimrecPred p} {f : α → Subtype p} :
    haveI := Primcodable.subtype hp
    (Primrec fun a => (f a).1) ↔ Primrec f := by
  letI := Primcodable.subtype hp
  refine' ⟨fun h => _, fun hf => subtype_val.comp hf⟩
  refine' Nat.Primrec.of_eq h fun n => _
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝⁴ : Primcodable α
inst✝³ : Primcodable β
inst✝² : Primcodable γ
inst✝¹ : Primcodable σ
p : β → Prop
inst✝ : DecidablePred p
hp : PrimrecPred p
f : α → Subtype p
this : Primcodable (Subtype p) := Primcodable.subtype hp
h : Primrec fun a => ↑(f a)
n : ℕ
⊢ encode (Option.map (fun a => ↑(f a)) (decode n)) = encode (Option.map f (decode n))

Next tactic:
cases' @decode α _ n with a
theorem subtype_val_iff {p : β → Prop} [DecidablePred p] {hp : PrimrecPred p} {f : α → Subtype p} :
    haveI := Primcodable.subtype hp
    (Primrec fun a => (f a).1) ↔ Primrec f := by
  letI := Primcodable.subtype hp
  refine' ⟨fun h => _, fun hf => subtype_val.comp hf⟩
  refine' Nat.Primrec.of_eq h fun n => _
  cases' @decode α _ n with a; · 

Proof state:
case none
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝⁴ : Primcodable α
inst✝³ : Primcodable β
inst✝² : Primcodable γ
inst✝¹ : Primcodable σ
p : β → Prop
inst✝ : DecidablePred p
hp : PrimrecPred p
f : α → Subtype p
this : Primcodable (Subtype p) := Primcodable.subtype hp
h : Primrec fun a => ↑(f a)
n : ℕ
⊢ encode (Option.map (fun a => ↑(f a)) none) = encode (Option.map f none)

Next tactic:
rfl
theorem subtype_val_iff {p : β → Prop} [DecidablePred p] {hp : PrimrecPred p} {f : α → Subtype p} :
    haveI := Primcodable.subtype hp
    (Primrec fun a => (f a).1) ↔ Primrec f := by
  letI := Primcodable.subtype hp
  refine' ⟨fun h => _, fun hf => subtype_val.comp hf⟩
  refine' Nat.Primrec.of_eq h fun n => _
  cases' @decode α _ n with a; · rfl
  

Proof state:
case some
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝⁴ : Primcodable α
inst✝³ : Primcodable β
inst✝² : Primcodable γ
inst✝¹ : Primcodable σ
p : β → Prop
inst✝ : DecidablePred p
hp : PrimrecPred p
f : α → Subtype p
this : Primcodable (Subtype p) := Primcodable.subtype hp
h : Primrec fun a => ↑(f a)
n : ℕ
a : α
⊢ encode (Option.map (fun a => ↑(f a)) (some a)) = encode (Option.map f (some a))

Next tactic:
simp
theorem subtype_val_iff {p : β → Prop} [DecidablePred p] {hp : PrimrecPred p} {f : α → Subtype p} :
    haveI := Primcodable.subtype hp
    (Primrec fun a => (f a).1) ↔ Primrec f := by
  letI := Primcodable.subtype hp
  refine' ⟨fun h => _, fun hf => subtype_val.comp hf⟩
  refine' Nat.Primrec.of_eq h fun n => _
  cases' @decode α _ n with a; · rfl
  simp; 

Proof state:
case some
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝⁴ : Primcodable α
inst✝³ : Primcodable β
inst✝² : Primcodable γ
inst✝¹ : Primcodable σ
p : β → Prop
inst✝ : DecidablePred p
hp : PrimrecPred p
f : α → Subtype p
this : Primcodable (Subtype p) := Primcodable.subtype hp
h : Primrec fun a => ↑(f a)
n : ℕ
a : α
⊢ Nat.succ (encode ↑(f a)) = encode (some (f a))

Next tactic:
rfl
theorem option_get {f : α → Option β} {h : ∀ a, (f a).isSome} :
    Primrec f → Primrec fun a => (f a).get (h a) := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
f : α → Option β
h : ∀ (a : α), Option.isSome (f a) = true
⊢ Primrec f → Primrec fun a => Option.get (f a) (_ : Option.isSome (f a) = true)

Next tactic:
intro hf
theorem option_get {f : α → Option β} {h : ∀ a, (f a).isSome} :
    Primrec f → Primrec fun a => (f a).get (h a) := by
  intro hf
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
f : α → Option β
h : ∀ (a : α), Option.isSome (f a) = true
hf : Primrec f
⊢ Primrec fun a => Option.get (f a) (_ : Option.isSome (f a) = true)

Next tactic:
refine' (Nat.Primrec.pred.comp hf).of_eq fun n => _
theorem option_get {f : α → Option β} {h : ∀ a, (f a).isSome} :
    Primrec f → Primrec fun a => (f a).get (h a) := by
  intro hf
  refine' (Nat.Primrec.pred.comp hf).of_eq fun n => _
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
f : α → Option β
h : ∀ (a : α), Option.isSome (f a) = true
hf : Primrec f
n : ℕ
⊢ Nat.pred (encode (Option.map f (decode n))) =
    encode (Option.map (fun a => Option.get (f a) (_ : Option.isSome (f a) = true)) (decode n))

Next tactic:
generalize hx : @decode α _ n = x
theorem option_get {f : α → Option β} {h : ∀ a, (f a).isSome} :
    Primrec f → Primrec fun a => (f a).get (h a) := by
  intro hf
  refine' (Nat.Primrec.pred.comp hf).of_eq fun n => _
  generalize hx : @decode α _ n = x
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
f : α → Option β
h : ∀ (a : α), Option.isSome (f a) = true
hf : Primrec f
n : ℕ
x : Option α
hx : decode n = x
⊢ Nat.pred (encode (Option.map f x)) =
    encode (Option.map (fun a => Option.get (f a) (_ : Option.isSome (f a) = true)) x)

Next tactic:
cases x
theorem option_get {f : α → Option β} {h : ∀ a, (f a).isSome} :
    Primrec f → Primrec fun a => (f a).get (h a) := by
  intro hf
  refine' (Nat.Primrec.pred.comp hf).of_eq fun n => _
  generalize hx : @decode α _ n = x
  cases x <;> 

Proof state:
case none
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
f : α → Option β
h : ∀ (a : α), Option.isSome (f a) = true
hf : Primrec f
n : ℕ
hx : decode n = none
⊢ Nat.pred (encode (Option.map f none)) =
    encode (Option.map (fun a => Option.get (f a) (_ : Option.isSome (f a) = true)) none)

Next tactic:
simp
theorem option_get {f : α → Option β} {h : ∀ a, (f a).isSome} :
    Primrec f → Primrec fun a => (f a).get (h a) := by
  intro hf
  refine' (Nat.Primrec.pred.comp hf).of_eq fun n => _
  generalize hx : @decode α _ n = x
  cases x <;> 

Proof state:
case some
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
f : α → Option β
h : ∀ (a : α), Option.isSome (f a) = true
hf : Primrec f
n : ℕ
val✝ : α
hx : decode n = some val✝
⊢ Nat.pred (encode (Option.map f (some val✝))) =
    encode (Option.map (fun a => Option.get (f a) (_ : Option.isSome (f a) = true)) (some val✝))

Next tactic:
simp
theorem fin_val_iff {n} {f : α → Fin n} : (Primrec fun a => (f a).1) ↔ Primrec f := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
f : α → Fin n
⊢ (Primrec fun a => ↑(f a)) ↔ Primrec f

Next tactic:
letI : Primcodable { a // id a < n } := Primcodable.subtype (nat_lt.comp .id (const _))
theorem fin_val_iff {n} {f : α → Fin n} : (Primrec fun a => (f a).1) ↔ Primrec f := by
  letI : Primcodable { a // id a < n } := Primcodable.subtype (nat_lt.comp .id (const _))
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
f : α → Fin n
this : Primcodable { a // id a < n } := Primcodable.subtype (_ : PrimrecPred fun a => id a < n)
⊢ (Primrec fun a => ↑(f a)) ↔ Primrec f

Next tactic:
exact (Iff.trans (by rfl) subtype_val_iff).trans (of_equiv_iff _)
theorem fin_val_iff {n} {f : α → Fin n} : (Primrec fun a => (f a).1) ↔ Primrec f := by
  letI : Primcodable { a // id a < n } := Primcodable.subtype (nat_lt.comp .id (const _))
  exact (Iff.trans (by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
f : α → Fin n
this : Primcodable { a // id a < n } := Primcodable.subtype (_ : PrimrecPred fun a => id a < n)
⊢ (Primrec fun a => ↑(f a)) ↔ Primrec fun a => ↑(Fin.equivSubtype (f a))

Next tactic:
rfl
theorem fin_succ {n} : Primrec (@Fin.succ n) :=
  fin_val_iff.1 <| by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
⊢ Primrec fun a => ↑(Fin.succ a)

Next tactic:
simp [succ.comp fin_val]
theorem vector_cons {n} : Primrec₂ (@Vector.cons α n) :=
  vector_toList_iff.1 <| by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
⊢ Primrec fun a => Vector.toList (a.1 ::ᵥ a.2)

Next tactic:
simp
theorem vector_cons {n} : Primrec₂ (@Vector.cons α n) :=
  vector_toList_iff.1 <| by simp; 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
⊢ Primrec fun a => a.1 :: Vector.toList a.2

Next tactic:
exact list_cons.comp fst (vector_toList_iff.2 snd)
theorem vector_tail {n} : Primrec (@Vector.tail α n) :=
  vector_toList_iff.1 <| (list_tail.comp vector_toList).of_eq fun ⟨l, h⟩ => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
x✝ : Vector α n
l : List α
h : List.length l = n
⊢ List.tail (Vector.toList { val := l, property := h }) = Vector.toList (Vector.tail { val := l, property := h })

Next tactic:
cases l
theorem vector_tail {n} : Primrec (@Vector.tail α n) :=
  vector_toList_iff.1 <| (list_tail.comp vector_toList).of_eq fun ⟨l, h⟩ => by cases l <;> 

Proof state:
case nil
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
x✝ : Vector α n
h : List.length [] = n
⊢ List.tail (Vector.toList { val := [], property := h }) = Vector.toList (Vector.tail { val := [], property := h })

Next tactic:
rfl
theorem vector_tail {n} : Primrec (@Vector.tail α n) :=
  vector_toList_iff.1 <| (list_tail.comp vector_toList).of_eq fun ⟨l, h⟩ => by cases l <;> 

Proof state:
case cons
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
x✝ : Vector α n
head✝ : α
tail✝ : List α
h : List.length (head✝ :: tail✝) = n
⊢ List.tail (Vector.toList { val := head✝ :: tail✝, property := h }) =
    Vector.toList (Vector.tail { val := head✝ :: tail✝, property := h })

Next tactic:
rfl
theorem vector_get {n} : Primrec₂ (@Vector.get α n) :=
  option_some_iff.1 <|
    (list_get?.comp (vector_toList.comp fst) (fin_val.comp snd)).of_eq fun a => by
      

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
a : Vector α n × Fin n
⊢ List.get? (Vector.toList a.1) ↑a.2 = some (Vector.get a.1 a.2)

Next tactic:
rw [Vector.get_eq_get, ← List.get?_eq_get]
theorem vector_get {n} : Primrec₂ (@Vector.get α n) :=
  option_some_iff.1 <|
    (list_get?.comp (vector_toList.comp fst) (fin_val.comp snd)).of_eq fun a => by
      rw [Vector.get_eq_get, ← List.get?_eq_get]
      

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
a : Vector α n × Fin n
⊢ List.get? (Vector.toList a.1) ↑a.2 =
    List.get? (Vector.toList a.1) ↑(Fin.cast (_ : n = List.length (Vector.toList a.1)) a.2)

Next tactic:
rfl
theorem list_ofFn :
    ∀ {n} {f : Fin n → α → σ}, (∀ i, Primrec (f i)) → Primrec fun a => List.ofFn fun i => f i a
  | 0, _, _ => const []
  | n + 1, f, hf => by
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
f : Fin (n + 1) → α → σ
hf : ∀ (i : Fin (n + 1)), Primrec (f i)
⊢ Primrec fun a => List.ofFn fun i => f i a

Next tactic:
simp [List.ofFn_succ]
theorem list_ofFn :
    ∀ {n} {f : Fin n → α → σ}, (∀ i, Primrec (f i)) → Primrec fun a => List.ofFn fun i => f i a
  | 0, _, _ => const []
  | n + 1, f, hf => by
    simp [List.ofFn_succ]; 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
f : Fin (n + 1) → α → σ
hf : ∀ (i : Fin (n + 1)), Primrec (f i)
⊢ Primrec fun a => f 0 a :: List.ofFn fun i => f (Fin.succ i) a

Next tactic:
exact list_cons.comp (hf 0) (list_ofFn fun i => hf i.succ)
theorem vector_ofFn {n} {f : Fin n → α → σ} (hf : ∀ i, Primrec (f i)) :
    Primrec fun a => Vector.ofFn fun i => f i a :=
  vector_toList_iff.1 <| by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
f : Fin n → α → σ
hf : ∀ (i : Fin n), Primrec (f i)
⊢ Primrec fun a => Vector.toList (Vector.ofFn fun i => f i a)

Next tactic:
simp [list_ofFn hf]
theorem fin_app {n} : Primrec₂ (@id (Fin n → σ)) :=
  (vector_get.comp (vector_ofFn'.comp fst) snd).of_eq fun ⟨v, i⟩ => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
x✝ : (Fin n → σ) × Fin n
v : Fin n → σ
i : Fin n
⊢ Vector.get (Vector.ofFn (v, i).1) (v, i).2 = id (v, i).1 (v, i).2

Next tactic:
simp
theorem fin_curry₁ {n} {f : Fin n → α → σ} : Primrec₂ f ↔ ∀ i, Primrec (f i) :=
  ⟨fun h i => h.comp (const i) .id, fun h =>
    (vector_get.comp ((vector_ofFn h).comp snd) fst).of_eq fun a => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
f : Fin n → α → σ
h : ∀ (i : Fin n), Primrec (f i)
a : Fin n × α
⊢ Vector.get (Vector.ofFn fun i => f i a.2) a.1 = f a.1 a.2

Next tactic:
simp
theorem fin_curry {n} {f : α → Fin n → σ} : Primrec f ↔ Primrec₂ f :=
  ⟨fun h => fin_app.comp (h.comp fst) snd, fun h =>
    (vector_get'.comp
          (vector_ofFn fun i => show Primrec fun a => f a i from h.comp .id (const i))).of_eq
      fun a => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
f : α → Fin n → σ
h : Primrec₂ f
a : α
⊢ Vector.get (Vector.ofFn fun i => f a i) = f a

Next tactic:
funext i
theorem fin_curry {n} {f : α → Fin n → σ} : Primrec f ↔ Primrec₂ f :=
  ⟨fun h => fin_app.comp (h.comp fst) snd, fun h =>
    (vector_get'.comp
          (vector_ofFn fun i => show Primrec fun a => f a i from h.comp .id (const i))).of_eq
      fun a => by funext i; 

Proof state:
case h
α : Type u_1
β : Type u_2
γ : Type u_3
σ : Type u_4
inst✝³ : Primcodable α
inst✝² : Primcodable β
inst✝¹ : Primcodable γ
inst✝ : Primcodable σ
n : ℕ
f : α → Fin n → σ
h : Primrec₂ f
a : α
i : Fin n
⊢ Vector.get (Vector.ofFn fun i => f a i) i = f a i

Next tactic:
simp
theorem to_prim {n f} (pf : @Nat.Primrec' n f) : Primrec f := by
  

Proof state:
n : ℕ
f : Vector ℕ n → ℕ
pf : Primrec' f
⊢ Primrec f

Next tactic:
induction pf
theorem to_prim {n f} (pf : @Nat.Primrec' n f) : Primrec f := by
  induction pf
  

Proof state:
case zero
n : ℕ
f : Vector ℕ n → ℕ
⊢ Primrec fun x => 0
case succ
n : ℕ
f : Vector ℕ n → ℕ
⊢ Primrec fun v => Nat.succ (head v)
case get
n : ℕ
f : Vector ℕ n → ℕ
n✝ : ℕ
i✝ : Fin n✝
⊢ Primrec fun v => Vector.get v i✝
case comp
n : ℕ
f : Vector ℕ n → ℕ
m✝ n✝ : ℕ
f✝ : Vector ℕ n✝ → ℕ
g✝ : Fin n✝ → Vector ℕ m✝ → ℕ
a✝¹ : Primrec' f✝
a✝ : ∀ (i : Fin n✝), Primrec' (g✝ i)
a_ih✝¹ : Primrec f✝
a_ih✝ : ∀ (i : Fin n✝), Primrec (g✝ i)
⊢ Primrec fun a => f✝ (ofFn fun i => g✝ i a)
case prec
n : ℕ
f : Vector ℕ n → ℕ
n✝ : ℕ
f✝ : Vector ℕ n✝ → ℕ
g✝ : Vector ℕ (n✝ + 2) → ℕ
a✝¹ : Primrec' f✝
a✝ : Primrec' g✝
a_ih✝¹ : Primrec f✝
a_ih✝ : Primrec g✝
⊢ Primrec fun v => Nat.rec (f✝ (tail v)) (fun y IH => g✝ (y ::ᵥ IH ::ᵥ tail v)) (head v)

Next tactic:
case zero => exact .const 0
theorem to_prim {n f} (pf : @Nat.Primrec' n f) : Primrec f := by
  induction pf
  

Proof state:
n : ℕ
f : Vector ℕ n → ℕ
⊢ Primrec fun x => 0

Next tactic:
case zero => exact .const 0
theorem to_prim {n f} (pf : @Nat.Primrec' n f) : Primrec f := by
  induction pf
  case zero => 

Proof state:
n : ℕ
f : Vector ℕ n → ℕ
⊢ Primrec fun x => 0

Next tactic:
exact .const 0