l3lab/ntp-mathlib huggingface dataset:
theorem cont_eval_fix {f k v} (fok : Code.Ok f) :
    Turing.eval step (stepNormal f (Cont.fix f k) v) =
      f.fix.eval v >>= fun v => Turing.eval step (Cfg.ret k v) := by
  refine' Part.ext fun x => _
  simp only [Part.bind_eq_bind, Part.mem_bind_iff]
  constructor
  · suffices ∀ c, x ∈ eval step c → ∀ v c', c = Cfg.then c' (Cont.fix f k) →
      Reaches step (stepNormal f Cont.halt v) c' →
        ∃ v₁ ∈ f.eval v, ∃ v₂ ∈ if List.headI v₁ = 0 then pure v₁.tail else f.fix.eval v₁.tail,
          x ∈ eval step (Cfg.ret k v₂) by
      intro h
      obtain ⟨v₁, hv₁, v₂, hv₂, h₃⟩ :=
        this _ h _ _ (stepNormal_then _ Cont.halt _ _) ReflTransGen.refl
      refine' ⟨v₂, PFun.mem_fix_iff.2 _, h₃⟩
      simp only [Part.eq_some_iff.2 hv₁, Part.map_some]
      split_ifs at hv₂ ⊢
      · rw [Part.mem_some_iff.1 hv₂]
        exact Or.inl (Part.mem_some _)
      · exact Or.inr ⟨_, Part.mem_some _, hv₂⟩
    refine' fun c he => evalInduction he fun y h IH => _
    rintro v (⟨v'⟩ | ⟨k', v'⟩) rfl hr <;> rw [Cfg.then] at h IH <;> simp only [] at h IH
    · have := mem_eval.2 ⟨hr, rfl⟩
      rw [fok, Part.bind_eq_bind, Part.mem_bind_iff] at this
      obtain ⟨v'', h₁, h₂⟩ := this
      rw [reaches_eval] at h₂
      swap
      exact ReflTransGen.single rfl
      cases Part.mem_unique h₂ (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
      refine' ⟨v', h₁, _⟩
      rw [stepRet] at h
      revert h
      by_cases he : v'.headI = 0 <;> simp only [exists_prop, if_pos, if_false, he] <;> intro h
      · refine' ⟨_, Part.mem_some _, _⟩
        rw [reaches_eval]
        exact h
        exact ReflTransGen.single rfl
      · obtain ⟨k₀, v₀, e₀⟩ := stepNormal.is_ret f Cont.halt v'.tail
        have e₁ := stepNormal_then f Cont.halt (Cont.fix f k) v'.tail
        rw [e₀, Cont.then, Cfg.then] at e₁
        simp only [] at e₁
        obtain ⟨v₁, hv₁, v₂, hv₂, h₃⟩ :=
          IH (stepRet (k₀.then (Cont.fix f k)) v₀) (by rw [stepRet, if_neg he, e₁]; rfl)
            v'.tail _ stepRet_then (by apply ReflTransGen.single; rw [e₀]; rfl)
        · refine' ⟨_, PFun.mem_fix_iff.2 _, h₃⟩
          simp only [Part.eq_some_iff.2 hv₁, Part.map_some, Part.mem_some_iff]
          split_ifs at hv₂ ⊢ <;> [exact Or.inl (congr_arg Sum.inl (Part.mem_some_iff.1 hv₂));
            exact Or.inr ⟨_, rfl, hv₂⟩]
    · exact IH _ rfl _ _ stepRet_then (ReflTransGen.tail hr rfl)
  · rintro ⟨v', he, hr⟩
    rw [reaches_eval] at hr
    swap
    exact ReflTransGen.single rfl
    

Proof state:
case mpr.intro.intro
f : Code
k : Cont
v : List ℕ
fok : Code.Ok f
x : Cfg
v' : List ℕ
he : v' ∈ Code.eval (Code.fix f) v
hr✝ : x ∈ eval step (Cfg.ret k v')
hr : x ∈ eval step (stepRet k v')
⊢ x ∈ eval step (stepNormal f (Cont.fix f k) v)

Next tactic:
refine' PFun.fixInduction he fun v (he : v' ∈ f.fix.eval v) IH => _
theorem cont_eval_fix {f k v} (fok : Code.Ok f) :
    Turing.eval step (stepNormal f (Cont.fix f k) v) =
      f.fix.eval v >>= fun v => Turing.eval step (Cfg.ret k v) := by
  refine' Part.ext fun x => _
  simp only [Part.bind_eq_bind, Part.mem_bind_iff]
  constructor
  · suffices ∀ c, x ∈ eval step c → ∀ v c', c = Cfg.then c' (Cont.fix f k) →
      Reaches step (stepNormal f Cont.halt v) c' →
        ∃ v₁ ∈ f.eval v, ∃ v₂ ∈ if List.headI v₁ = 0 then pure v₁.tail else f.fix.eval v₁.tail,
          x ∈ eval step (Cfg.ret k v₂) by
      intro h
      obtain ⟨v₁, hv₁, v₂, hv₂, h₃⟩ :=
        this _ h _ _ (stepNormal_then _ Cont.halt _ _) ReflTransGen.refl
      refine' ⟨v₂, PFun.mem_fix_iff.2 _, h₃⟩
      simp only [Part.eq_some_iff.2 hv₁, Part.map_some]
      split_ifs at hv₂ ⊢
      · rw [Part.mem_some_iff.1 hv₂]
        exact Or.inl (Part.mem_some _)
      · exact Or.inr ⟨_, Part.mem_some _, hv₂⟩
    refine' fun c he => evalInduction he fun y h IH => _
    rintro v (⟨v'⟩ | ⟨k', v'⟩) rfl hr <;> rw [Cfg.then] at h IH <;> simp only [] at h IH
    · have := mem_eval.2 ⟨hr, rfl⟩
      rw [fok, Part.bind_eq_bind, Part.mem_bind_iff] at this
      obtain ⟨v'', h₁, h₂⟩ := this
      rw [reaches_eval] at h₂
      swap
      exact ReflTransGen.single rfl
      cases Part.mem_unique h₂ (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
      refine' ⟨v', h₁, _⟩
      rw [stepRet] at h
      revert h
      by_cases he : v'.headI = 0 <;> simp only [exists_prop, if_pos, if_false, he] <;> intro h
      · refine' ⟨_, Part.mem_some _, _⟩
        rw [reaches_eval]
        exact h
        exact ReflTransGen.single rfl
      · obtain ⟨k₀, v₀, e₀⟩ := stepNormal.is_ret f Cont.halt v'.tail
        have e₁ := stepNormal_then f Cont.halt (Cont.fix f k) v'.tail
        rw [e₀, Cont.then, Cfg.then] at e₁
        simp only [] at e₁
        obtain ⟨v₁, hv₁, v₂, hv₂, h₃⟩ :=
          IH (stepRet (k₀.then (Cont.fix f k)) v₀) (by rw [stepRet, if_neg he, e₁]; rfl)
            v'.tail _ stepRet_then (by apply ReflTransGen.single; rw [e₀]; rfl)
        · refine' ⟨_, PFun.mem_fix_iff.2 _, h₃⟩
          simp only [Part.eq_some_iff.2 hv₁, Part.map_some, Part.mem_some_iff]
          split_ifs at hv₂ ⊢ <;> [exact Or.inl (congr_arg Sum.inl (Part.mem_some_iff.1 hv₂));
            exact Or.inr ⟨_, rfl, hv₂⟩]
    · exact IH _ rfl _ _ stepRet_then (ReflTransGen.tail hr rfl)
  · rintro ⟨v', he, hr⟩
    rw [reaches_eval] at hr
    swap
    exact ReflTransGen.single rfl
    refine' PFun.fixInduction he fun v (he : v' ∈ f.fix.eval v) IH => _
    

Proof state:
case mpr.intro.intro
f : Code
k : Cont
v✝ : List ℕ
fok : Code.Ok f
x : Cfg
v' : List ℕ
he✝ : v' ∈ Code.eval (Code.fix f) v✝
hr✝ : x ∈ eval step (Cfg.ret k v')
hr : x ∈ eval step (stepRet k v')
v : List ℕ
he : v' ∈ Code.eval (Code.fix f) v
IH :
  ∀ (a'' : List ℕ),
    Sum.inr a'' ∈
        Part.map (fun v => if List.headI v = 0 then Sum.inl (List.tail v) else Sum.inr (List.tail v)) (Code.eval f v) →
      x ∈ eval step (stepNormal f (Cont.fix f k) a'')
⊢ x ∈ eval step (stepNormal f (Cont.fix f k) v)

Next tactic:
rw [fok, Part.bind_eq_bind, Part.mem_bind_iff]
theorem cont_eval_fix {f k v} (fok : Code.Ok f) :
    Turing.eval step (stepNormal f (Cont.fix f k) v) =
      f.fix.eval v >>= fun v => Turing.eval step (Cfg.ret k v) := by
  refine' Part.ext fun x => _
  simp only [Part.bind_eq_bind, Part.mem_bind_iff]
  constructor
  · suffices ∀ c, x ∈ eval step c → ∀ v c', c = Cfg.then c' (Cont.fix f k) →
      Reaches step (stepNormal f Cont.halt v) c' →
        ∃ v₁ ∈ f.eval v, ∃ v₂ ∈ if List.headI v₁ = 0 then pure v₁.tail else f.fix.eval v₁.tail,
          x ∈ eval step (Cfg.ret k v₂) by
      intro h
      obtain ⟨v₁, hv₁, v₂, hv₂, h₃⟩ :=
        this _ h _ _ (stepNormal_then _ Cont.halt _ _) ReflTransGen.refl
      refine' ⟨v₂, PFun.mem_fix_iff.2 _, h₃⟩
      simp only [Part.eq_some_iff.2 hv₁, Part.map_some]
      split_ifs at hv₂ ⊢
      · rw [Part.mem_some_iff.1 hv₂]
        exact Or.inl (Part.mem_some _)
      · exact Or.inr ⟨_, Part.mem_some _, hv₂⟩
    refine' fun c he => evalInduction he fun y h IH => _
    rintro v (⟨v'⟩ | ⟨k', v'⟩) rfl hr <;> rw [Cfg.then] at h IH <;> simp only [] at h IH
    · have := mem_eval.2 ⟨hr, rfl⟩
      rw [fok, Part.bind_eq_bind, Part.mem_bind_iff] at this
      obtain ⟨v'', h₁, h₂⟩ := this
      rw [reaches_eval] at h₂
      swap
      exact ReflTransGen.single rfl
      cases Part.mem_unique h₂ (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
      refine' ⟨v', h₁, _⟩
      rw [stepRet] at h
      revert h
      by_cases he : v'.headI = 0 <;> simp only [exists_prop, if_pos, if_false, he] <;> intro h
      · refine' ⟨_, Part.mem_some _, _⟩
        rw [reaches_eval]
        exact h
        exact ReflTransGen.single rfl
      · obtain ⟨k₀, v₀, e₀⟩ := stepNormal.is_ret f Cont.halt v'.tail
        have e₁ := stepNormal_then f Cont.halt (Cont.fix f k) v'.tail
        rw [e₀, Cont.then, Cfg.then] at e₁
        simp only [] at e₁
        obtain ⟨v₁, hv₁, v₂, hv₂, h₃⟩ :=
          IH (stepRet (k₀.then (Cont.fix f k)) v₀) (by rw [stepRet, if_neg he, e₁]; rfl)
            v'.tail _ stepRet_then (by apply ReflTransGen.single; rw [e₀]; rfl)
        · refine' ⟨_, PFun.mem_fix_iff.2 _, h₃⟩
          simp only [Part.eq_some_iff.2 hv₁, Part.map_some, Part.mem_some_iff]
          split_ifs at hv₂ ⊢ <;> [exact Or.inl (congr_arg Sum.inl (Part.mem_some_iff.1 hv₂));
            exact Or.inr ⟨_, rfl, hv₂⟩]
    · exact IH _ rfl _ _ stepRet_then (ReflTransGen.tail hr rfl)
  · rintro ⟨v', he, hr⟩
    rw [reaches_eval] at hr
    swap
    exact ReflTransGen.single rfl
    refine' PFun.fixInduction he fun v (he : v' ∈ f.fix.eval v) IH => _
    rw [fok, Part.bind_eq_bind, Part.mem_bind_iff]
    

Proof state:
case mpr.intro.intro
f : Code
k : Cont
v✝ : List ℕ
fok : Code.Ok f
x : Cfg
v' : List ℕ
he✝ : v' ∈ Code.eval (Code.fix f) v✝
hr✝ : x ∈ eval step (Cfg.ret k v')
hr : x ∈ eval step (stepRet k v')
v : List ℕ
he : v' ∈ Code.eval (Code.fix f) v
IH :
  ∀ (a'' : List ℕ),
    Sum.inr a'' ∈
        Part.map (fun v => if List.headI v = 0 then Sum.inl (List.tail v) else Sum.inr (List.tail v)) (Code.eval f v) →
      x ∈ eval step (stepNormal f (Cont.fix f k) a'')
⊢ ∃ a ∈ Code.eval f v, x ∈ eval step (Cfg.ret (Cont.fix f k) a)

Next tactic:
obtain he | ⟨v'', he₁', _⟩ := PFun.mem_fix_iff.1 he
theorem code_is_ok (c) : Code.Ok c := by
  

Proof state:
c : Code
⊢ Code.Ok c

Next tactic:
induction c
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> 

Proof state:
case zero'
⊢ Code.Ok Code.zero'

Next tactic:
intro k v
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> 

Proof state:
case succ
⊢ Code.Ok Code.succ

Next tactic:
intro k v
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> 

Proof state:
case tail
⊢ Code.Ok Code.tail

Next tactic:
intro k v
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> 

Proof state:
case cons
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
⊢ Code.Ok (Code.cons a✝¹ a✝)

Next tactic:
intro k v
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> 

Proof state:
case comp
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
⊢ Code.Ok (Code.comp a✝¹ a✝)

Next tactic:
intro k v
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> 

Proof state:
case case
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
⊢ Code.Ok (Code.case a✝¹ a✝)

Next tactic:
intro k v
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> 

Proof state:
case fix
a✝ : Code
a_ih✝ : Code.Ok a✝
⊢ Code.Ok (Code.fix a✝)

Next tactic:
intro k v
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> 

Proof state:
case zero'
k : Cont
v : List ℕ
⊢ eval step (stepNormal Code.zero' k v) = do
    let v ← Code.eval Code.zero' v
    eval step (Cfg.ret k v)

Next tactic:
rw [stepNormal]
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> 

Proof state:
case succ
k : Cont
v : List ℕ
⊢ eval step (stepNormal Code.succ k v) = do
    let v ← Code.eval Code.succ v
    eval step (Cfg.ret k v)

Next tactic:
rw [stepNormal]
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> 

Proof state:
case tail
k : Cont
v : List ℕ
⊢ eval step (stepNormal Code.tail k v) = do
    let v ← Code.eval Code.tail v
    eval step (Cfg.ret k v)

Next tactic:
rw [stepNormal]
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> 

Proof state:
case cons
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step (stepNormal (Code.cons a✝¹ a✝) k v) = do
    let v ← Code.eval (Code.cons a✝¹ a✝) v
    eval step (Cfg.ret k v)

Next tactic:
rw [stepNormal]
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> 

Proof state:
case comp
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step (stepNormal (Code.comp a✝¹ a✝) k v) = do
    let v ← Code.eval (Code.comp a✝¹ a✝) v
    eval step (Cfg.ret k v)

Next tactic:
rw [stepNormal]
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> 

Proof state:
case case
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step (stepNormal (Code.case a✝¹ a✝) k v) = do
    let v ← Code.eval (Code.case a✝¹ a✝) v
    eval step (Cfg.ret k v)

Next tactic:
rw [stepNormal]
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> 

Proof state:
case fix
a✝ : Code
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step (stepNormal (Code.fix a✝) k v) = do
    let v ← Code.eval (Code.fix a✝) v
    eval step (Cfg.ret k v)

Next tactic:
rw [stepNormal]
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> rw [stepNormal]
  

Proof state:
case zero'
k : Cont
v : List ℕ
⊢ eval step ((fun k v => Cfg.ret k (0 :: v)) k v) = do
    let v ← Code.eval Code.zero' v
    eval step (Cfg.ret k v)
case succ
k : Cont
v : List ℕ
⊢ eval step ((fun k v => Cfg.ret k [Nat.succ (List.headI v)]) k v) = do
    let v ← Code.eval Code.succ v
    eval step (Cfg.ret k v)
case tail
k : Cont
v : List ℕ
⊢ eval step ((fun k v => Cfg.ret k (List.tail v)) k v) = do
    let v ← Code.eval Code.tail v
    eval step (Cfg.ret k v)
case cons
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal a✝¹ (Cont.cons₁ a✝ v k) v) k v) = do
    let v ← Code.eval (Code.cons a✝¹ a✝) v
    eval step (Cfg.ret k v)
case comp
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal a✝ (Cont.comp a✝¹ k) v) k v) = do
    let v ← Code.eval (Code.comp a✝¹ a✝) v
    eval step (Cfg.ret k v)
case case
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step
      ((fun k v =>
          Nat.rec (stepNormal a✝¹ k (List.tail v)) (fun y x => stepNormal a✝ k (y :: List.tail v)) (List.headI v))
        k v) =
    do
    let v ← Code.eval (Code.case a✝¹ a✝) v
    eval step (Cfg.ret k v)
case fix
a✝ : Code
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal a✝ (Cont.fix a✝ k) v) k v) = do
    let v ← Code.eval (Code.fix a✝) v
    eval step (Cfg.ret k v)

Next tactic:
iterate 3 simp only [Code.eval, pure_bind]
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> rw [stepNormal]
  iterate 3 

Proof state:
case zero'
k : Cont
v : List ℕ
⊢ eval step ((fun k v => Cfg.ret k (0 :: v)) k v) = do
    let v ← Code.eval Code.zero' v
    eval step (Cfg.ret k v)
case succ
k : Cont
v : List ℕ
⊢ eval step ((fun k v => Cfg.ret k [Nat.succ (List.headI v)]) k v) = do
    let v ← Code.eval Code.succ v
    eval step (Cfg.ret k v)
case tail
k : Cont
v : List ℕ
⊢ eval step ((fun k v => Cfg.ret k (List.tail v)) k v) = do
    let v ← Code.eval Code.tail v
    eval step (Cfg.ret k v)
case cons
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal a✝¹ (Cont.cons₁ a✝ v k) v) k v) = do
    let v ← Code.eval (Code.cons a✝¹ a✝) v
    eval step (Cfg.ret k v)
case comp
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal a✝ (Cont.comp a✝¹ k) v) k v) = do
    let v ← Code.eval (Code.comp a✝¹ a✝) v
    eval step (Cfg.ret k v)
case case
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step
      ((fun k v =>
          Nat.rec (stepNormal a✝¹ k (List.tail v)) (fun y x => stepNormal a✝ k (y :: List.tail v)) (List.headI v))
        k v) =
    do
    let v ← Code.eval (Code.case a✝¹ a✝) v
    eval step (Cfg.ret k v)
case fix
a✝ : Code
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal a✝ (Cont.fix a✝ k) v) k v) = do
    let v ← Code.eval (Code.fix a✝) v
    eval step (Cfg.ret k v)

Next tactic:
simp only [Code.eval, pure_bind]
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> rw [stepNormal]
  iterate 3 

Proof state:
case succ
k : Cont
v : List ℕ
⊢ eval step ((fun k v => Cfg.ret k [Nat.succ (List.headI v)]) k v) = do
    let v ← Code.eval Code.succ v
    eval step (Cfg.ret k v)
case tail
k : Cont
v : List ℕ
⊢ eval step ((fun k v => Cfg.ret k (List.tail v)) k v) = do
    let v ← Code.eval Code.tail v
    eval step (Cfg.ret k v)
case cons
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal a✝¹ (Cont.cons₁ a✝ v k) v) k v) = do
    let v ← Code.eval (Code.cons a✝¹ a✝) v
    eval step (Cfg.ret k v)
case comp
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal a✝ (Cont.comp a✝¹ k) v) k v) = do
    let v ← Code.eval (Code.comp a✝¹ a✝) v
    eval step (Cfg.ret k v)
case case
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step
      ((fun k v =>
          Nat.rec (stepNormal a✝¹ k (List.tail v)) (fun y x => stepNormal a✝ k (y :: List.tail v)) (List.headI v))
        k v) =
    do
    let v ← Code.eval (Code.case a✝¹ a✝) v
    eval step (Cfg.ret k v)
case fix
a✝ : Code
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal a✝ (Cont.fix a✝ k) v) k v) = do
    let v ← Code.eval (Code.fix a✝) v
    eval step (Cfg.ret k v)

Next tactic:
simp only [Code.eval, pure_bind]
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> rw [stepNormal]
  iterate 3 

Proof state:
case tail
k : Cont
v : List ℕ
⊢ eval step ((fun k v => Cfg.ret k (List.tail v)) k v) = do
    let v ← Code.eval Code.tail v
    eval step (Cfg.ret k v)
case cons
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal a✝¹ (Cont.cons₁ a✝ v k) v) k v) = do
    let v ← Code.eval (Code.cons a✝¹ a✝) v
    eval step (Cfg.ret k v)
case comp
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal a✝ (Cont.comp a✝¹ k) v) k v) = do
    let v ← Code.eval (Code.comp a✝¹ a✝) v
    eval step (Cfg.ret k v)
case case
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step
      ((fun k v =>
          Nat.rec (stepNormal a✝¹ k (List.tail v)) (fun y x => stepNormal a✝ k (y :: List.tail v)) (List.headI v))
        k v) =
    do
    let v ← Code.eval (Code.case a✝¹ a✝) v
    eval step (Cfg.ret k v)
case fix
a✝ : Code
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal a✝ (Cont.fix a✝ k) v) k v) = do
    let v ← Code.eval (Code.fix a✝) v
    eval step (Cfg.ret k v)

Next tactic:
simp only [Code.eval, pure_bind]
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> rw [stepNormal]
  iterate 3 simp only [Code.eval, pure_bind]
  

Proof state:
case cons
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal a✝¹ (Cont.cons₁ a✝ v k) v) k v) = do
    let v ← Code.eval (Code.cons a✝¹ a✝) v
    eval step (Cfg.ret k v)
case comp
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal a✝ (Cont.comp a✝¹ k) v) k v) = do
    let v ← Code.eval (Code.comp a✝¹ a✝) v
    eval step (Cfg.ret k v)
case case
a✝¹ a✝ : Code
a_ih✝¹ : Code.Ok a✝¹
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step
      ((fun k v =>
          Nat.rec (stepNormal a✝¹ k (List.tail v)) (fun y x => stepNormal a✝ k (y :: List.tail v)) (List.headI v))
        k v) =
    do
    let v ← Code.eval (Code.case a✝¹ a✝) v
    eval step (Cfg.ret k v)
case fix
a✝ : Code
a_ih✝ : Code.Ok a✝
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal a✝ (Cont.fix a✝ k) v) k v) = do
    let v ← Code.eval (Code.fix a✝) v
    eval step (Cfg.ret k v)

Next tactic:
case cons f fs IHf IHfs =>
    rw [Code.eval, IHf]
    simp only [bind_assoc, Cont.eval, pure_bind]; congr; funext v
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IHfs]; congr; funext v'
    refine' Eq.trans _ (Eq.symm _) <;> try exact reaches_eval (ReflTransGen.single rfl)
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> rw [stepNormal]
  iterate 3 simp only [Code.eval, pure_bind]
  

Proof state:
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal f (Cont.cons₁ fs v k) v) k v) = do
    let v ← Code.eval (Code.cons f fs) v
    eval step (Cfg.ret k v)

Next tactic:
case cons f fs IHf IHfs =>
    rw [Code.eval, IHf]
    simp only [bind_assoc, Cont.eval, pure_bind]; congr; funext v
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IHfs]; congr; funext v'
    refine' Eq.trans _ (Eq.symm _) <;> try exact reaches_eval (ReflTransGen.single rfl)
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> rw [stepNormal]
  iterate 3 simp only [Code.eval, pure_bind]
  case cons f fs IHf IHfs =>
    

Proof state:
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v : List ℕ
⊢ eval step ((fun k v => stepNormal f (Cont.cons₁ fs v k) v) k v) = do
    let v ← Code.eval (Code.cons f fs) v
    eval step (Cfg.ret k v)

Next tactic:
rw [Code.eval, IHf]
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> rw [stepNormal]
  iterate 3 simp only [Code.eval, pure_bind]
  case cons f fs IHf IHfs =>
    rw [Code.eval, IHf]
    

Proof state:
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v : List ℕ
⊢ (do
      let v_1 ← Code.eval f v
      eval step (Cfg.ret (Cont.cons₁ fs v k) v_1)) =
    do
    let v ←
      (fun v => do
            let n ← Code.eval f v
            let ns ← Code.eval fs v
            pure (List.headI n :: ns))
          v
    eval step (Cfg.ret k v)

Next tactic:
simp only [bind_assoc, Cont.eval, pure_bind]
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> rw [stepNormal]
  iterate 3 simp only [Code.eval, pure_bind]
  case cons f fs IHf IHfs =>
    rw [Code.eval, IHf]
    simp only [bind_assoc, Cont.eval, pure_bind]; 

Proof state:
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v : List ℕ
⊢ (do
      let v_1 ← Code.eval f v
      eval step (Cfg.ret (Cont.cons₁ fs v k) v_1)) =
    do
    let x ← Code.eval f v
    let x_1 ← Code.eval fs v
    eval step (Cfg.ret k (List.headI x :: x_1))

Next tactic:
congr
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> rw [stepNormal]
  iterate 3 simp only [Code.eval, pure_bind]
  case cons f fs IHf IHfs =>
    rw [Code.eval, IHf]
    simp only [bind_assoc, Cont.eval, pure_bind]; congr; 

Proof state:
case e_a
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v : List ℕ
⊢ (fun v_1 => eval step (Cfg.ret (Cont.cons₁ fs v k) v_1)) = fun x => do
    let x_1 ← Code.eval fs v
    eval step (Cfg.ret k (List.headI x :: x_1))

Next tactic:
funext v
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> rw [stepNormal]
  iterate 3 simp only [Code.eval, pure_bind]
  case cons f fs IHf IHfs =>
    rw [Code.eval, IHf]
    simp only [bind_assoc, Cont.eval, pure_bind]; congr; funext v
    

Proof state:
case e_a.h
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v✝ v : List ℕ
⊢ eval step (Cfg.ret (Cont.cons₁ fs v✝ k) v) = do
    let x ← Code.eval fs v✝
    eval step (Cfg.ret k (List.headI v :: x))

Next tactic:
rw [reaches_eval]
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> rw [stepNormal]
  iterate 3 simp only [Code.eval, pure_bind]
  case cons f fs IHf IHfs =>
    rw [Code.eval, IHf]
    simp only [bind_assoc, Cont.eval, pure_bind]; congr; funext v
    rw [reaches_eval]; 

Proof state:
case e_a.h
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v✝ v : List ℕ
⊢ eval step ?m.226566 = do
    let x ← Code.eval fs v✝
    eval step (Cfg.ret k (List.headI v :: x))
case e_a.h
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v✝ v : List ℕ
⊢ Reaches step (Cfg.ret (Cont.cons₁ fs v✝ k) v) ?m.226566
f fs : Code IHf : Code.Ok f IHfs : Code.Ok fs k : Cont v✝ v : List ℕ ⊢ Cfg

Next tactic:
swap
theorem code_is_ok (c) : Code.Ok c := by
  induction c <;> intro k v <;> rw [stepNormal]
  iterate 3 simp only [Code.eval, pure_bind]
  case cons f fs IHf IHfs =>
    rw [Code.eval, IHf]
    simp only [bind_assoc, Cont.eval, pure_bind]; congr; funext v
    rw [reaches_eval]; swap; 

Proof state:
case e_a.h
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v✝ v : List ℕ
⊢ Reaches step (Cfg.ret (Cont.cons₁ fs v✝ k) v) ?m.226566
case e_a.h
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v✝ v : List ℕ
⊢ eval step ?m.226566 = do
    let x ← Code.eval fs v✝
    eval step (Cfg.ret k (List.headI v :: x))
f fs : Code IHf : Code.Ok f IHfs : Code.Ok fs k : Cont v✝ v : List ℕ ⊢ Cfg

Next tactic:
exact ReflTransGen.single rfl