l3lab/ntp-mathlib huggingface dataset:
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; exact ReflTransGen.single rfl
    rw [stepRet, IHfs]; congr; funext v'
    refine' Eq.trans _ (Eq.symm _) <;> try exact reaches_eval (ReflTransGen.single rfl)
  case comp f g IHf IHg =>
    rw [Code.eval, IHg]
    simp only [bind_assoc, Cont.eval, pure_bind]; congr; funext v
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IHf]
  case case f g IHf IHg =>
    simp only [Code.eval]
    cases v.headI <;> simp only [Code.eval] <;> [apply IHf; apply IHg]
  

Proof state:
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 fix f IHf => rw [cont_eval_fix 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]
    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)
  case comp f g IHf IHg =>
    rw [Code.eval, IHg]
    simp only [bind_assoc, Cont.eval, pure_bind]; congr; funext v
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IHf]
  case case f g IHf IHg =>
    simp only [Code.eval]
    cases v.headI <;> simp only [Code.eval] <;> [apply IHf; apply IHg]
  

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

Next tactic:
case fix f IHf => rw [cont_eval_fix 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]
    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)
  case comp f g IHf IHg =>
    rw [Code.eval, IHg]
    simp only [bind_assoc, Cont.eval, pure_bind]; congr; funext v
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IHf]
  case case f g IHf IHg =>
    simp only [Code.eval]
    cases v.headI <;> simp only [Code.eval] <;> [apply IHf; apply IHg]
  case fix f IHf => 

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

Next tactic:
rw [cont_eval_fix IHf]
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  

Proof state:
k : Cont
v : List ℕ
⊢ eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v

Next tactic:
induction k generalizing v
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  

Proof state:
case halt
v : List ℕ
⊢ eval step (stepRet Cont.halt v) = Cfg.halt <$> Cont.eval Cont.halt v
case cons₁
a✝² : Code
a✝¹ : List ℕ
a✝ : Cont
a_ih✝ : ∀ {v : List ℕ}, eval step (stepRet a✝ v) = Cfg.halt <$> Cont.eval a✝ v
v : List ℕ
⊢ eval step (stepRet (Cont.cons₁ a✝² a✝¹ a✝) v) = Cfg.halt <$> Cont.eval (Cont.cons₁ a✝² a✝¹ a✝) v
case cons₂
a✝¹ : List ℕ
a✝ : Cont
a_ih✝ : ∀ {v : List ℕ}, eval step (stepRet a✝ v) = Cfg.halt <$> Cont.eval a✝ v
v : List ℕ
⊢ eval step (stepRet (Cont.cons₂ a✝¹ a✝) v) = Cfg.halt <$> Cont.eval (Cont.cons₂ a✝¹ a✝) v
case comp
a✝¹ : Code
a✝ : Cont
a_ih✝ : ∀ {v : List ℕ}, eval step (stepRet a✝ v) = Cfg.halt <$> Cont.eval a✝ v
v : List ℕ
⊢ eval step (stepRet (Cont.comp a✝¹ a✝) v) = Cfg.halt <$> Cont.eval (Cont.comp a✝¹ a✝) v
case fix
a✝¹ : Code
a✝ : Cont
a_ih✝ : ∀ {v : List ℕ}, eval step (stepRet a✝ v) = Cfg.halt <$> Cont.eval a✝ v
v : List ℕ
⊢ eval step (stepRet (Cont.fix a✝¹ a✝) v) = Cfg.halt <$> Cont.eval (Cont.fix a✝¹ a✝) v

Next tactic:
case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  

Proof state:
v : List ℕ
⊢ eval step (stepRet Cont.halt v) = Cfg.halt <$> Cont.eval Cont.halt v

Next tactic:
case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    

Proof state:
v : List ℕ
⊢ eval step (stepRet Cont.halt v) = Cfg.halt <$> Cont.eval Cont.halt v

Next tactic:
simp only [mem_eval, Cont.eval, map_pure]
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    

Proof state:
v : List ℕ
⊢ eval step (stepRet Cont.halt v) = pure (Cfg.halt v)

Next tactic:
exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  

Proof state:
case cons₁
a✝² : Code
a✝¹ : List ℕ
a✝ : Cont
a_ih✝ : ∀ {v : List ℕ}, eval step (stepRet a✝ v) = Cfg.halt <$> Cont.eval a✝ v
v : List ℕ
⊢ eval step (stepRet (Cont.cons₁ a✝² a✝¹ a✝) v) = Cfg.halt <$> Cont.eval (Cont.cons₁ a✝² a✝¹ a✝) v
case cons₂
a✝¹ : List ℕ
a✝ : Cont
a_ih✝ : ∀ {v : List ℕ}, eval step (stepRet a✝ v) = Cfg.halt <$> Cont.eval a✝ v
v : List ℕ
⊢ eval step (stepRet (Cont.cons₂ a✝¹ a✝) v) = Cfg.halt <$> Cont.eval (Cont.cons₂ a✝¹ a✝) v
case comp
a✝¹ : Code
a✝ : Cont
a_ih✝ : ∀ {v : List ℕ}, eval step (stepRet a✝ v) = Cfg.halt <$> Cont.eval a✝ v
v : List ℕ
⊢ eval step (stepRet (Cont.comp a✝¹ a✝) v) = Cfg.halt <$> Cont.eval (Cont.comp a✝¹ a✝) v
case fix
a✝¹ : Code
a✝ : Cont
a_ih✝ : ∀ {v : List ℕ}, eval step (stepRet a✝ v) = Cfg.halt <$> Cont.eval a✝ v
v : List ℕ
⊢ eval step (stepRet (Cont.fix a✝¹ a✝) v) = Cfg.halt <$> Cont.eval (Cont.fix a✝¹ a✝) v

Next tactic:
case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IH, bind_pure_comp]
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  

Proof state:
fs : Code
as : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v : List ℕ
⊢ eval step (stepRet (Cont.cons₁ fs as k) v) = Cfg.halt <$> Cont.eval (Cont.cons₁ fs as k) v

Next tactic:
case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IH, bind_pure_comp]
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    

Proof state:
fs : Code
as : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v : List ℕ
⊢ eval step (stepRet (Cont.cons₁ fs as k) v) = Cfg.halt <$> Cont.eval (Cont.cons₁ fs as k) v

Next tactic:
rw [Cont.eval, stepRet, code_is_ok]
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    

Proof state:
fs : Code
as : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v : List ℕ
⊢ (do
      let v_1 ← Code.eval fs as
      eval step (Cfg.ret (Cont.cons₂ v k) v_1)) =
    Cfg.halt <$>
      (fun v => do
          let ns ← Code.eval fs as
          Cont.eval k (List.headI v :: ns))
        v

Next tactic:
simp only [← bind_pure_comp, bind_assoc]
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; 

Proof state:
fs : Code
as : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v : List ℕ
⊢ (do
      let v_1 ← Code.eval fs as
      eval step (Cfg.ret (Cont.cons₂ v k) v_1)) =
    do
    let x ← Code.eval fs as
    let a ← Cont.eval k (List.headI v :: x)
    pure (Cfg.halt a)

Next tactic:
congr
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; 

Proof state:
case e_a
fs : Code
as : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v : List ℕ
⊢ (fun v_1 => eval step (Cfg.ret (Cont.cons₂ v k) v_1)) = fun x => do
    let a ← Cont.eval k (List.headI v :: x)
    pure (Cfg.halt a)

Next tactic:
funext v'
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    

Proof state:
case e_a.h
fs : Code
as : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v v' : List ℕ
⊢ eval step (Cfg.ret (Cont.cons₂ v k) v') = do
    let a ← Cont.eval k (List.headI v :: v')
    pure (Cfg.halt a)

Next tactic:
rw [reaches_eval]
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; 

Proof state:
case e_a.h
fs : Code
as : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v v' : List ℕ
⊢ eval step ?m.229028 = do
    let a ← Cont.eval k (List.headI v :: v')
    pure (Cfg.halt a)
case e_a.h
fs : Code
as : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v v' : List ℕ
⊢ Reaches step (Cfg.ret (Cont.cons₂ v k) v') ?m.229028
fs : Code
as : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v v' : List ℕ
⊢ Cfg

Next tactic:
swap
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; 

Proof state:
case e_a.h
fs : Code
as : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v v' : List ℕ
⊢ Reaches step (Cfg.ret (Cont.cons₂ v k) v') ?m.229028
case e_a.h
fs : Code
as : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v v' : List ℕ
⊢ eval step ?m.229028 = do
    let a ← Cont.eval k (List.headI v :: v')
    pure (Cfg.halt a)
fs : Code
as : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v v' : List ℕ
⊢ Cfg

Next tactic:
exact ReflTransGen.single rfl
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    

Proof state:
case e_a.h
fs : Code
as : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v v' : List ℕ
⊢ eval step (stepRet (Cont.cons₂ v k) v') = do
    let a ← Cont.eval k (List.headI v :: v')
    pure (Cfg.halt a)

Next tactic:
rw [stepRet, IH, bind_pure_comp]
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IH, bind_pure_comp]
  

Proof state:
case cons₂
a✝¹ : List ℕ
a✝ : Cont
a_ih✝ : ∀ {v : List ℕ}, eval step (stepRet a✝ v) = Cfg.halt <$> Cont.eval a✝ v
v : List ℕ
⊢ eval step (stepRet (Cont.cons₂ a✝¹ a✝) v) = Cfg.halt <$> Cont.eval (Cont.cons₂ a✝¹ a✝) v
case comp
a✝¹ : Code
a✝ : Cont
a_ih✝ : ∀ {v : List ℕ}, eval step (stepRet a✝ v) = Cfg.halt <$> Cont.eval a✝ v
v : List ℕ
⊢ eval step (stepRet (Cont.comp a✝¹ a✝) v) = Cfg.halt <$> Cont.eval (Cont.comp a✝¹ a✝) v
case fix
a✝¹ : Code
a✝ : Cont
a_ih✝ : ∀ {v : List ℕ}, eval step (stepRet a✝ v) = Cfg.halt <$> Cont.eval a✝ v
v : List ℕ
⊢ eval step (stepRet (Cont.fix a✝¹ a✝) v) = Cfg.halt <$> Cont.eval (Cont.fix a✝¹ a✝) v

Next tactic:
case cons₂ ns k IH => rw [Cont.eval, stepRet]; exact IH
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IH, bind_pure_comp]
  

Proof state:
ns : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v : List ℕ
⊢ eval step (stepRet (Cont.cons₂ ns k) v) = Cfg.halt <$> Cont.eval (Cont.cons₂ ns k) v

Next tactic:
case cons₂ ns k IH => rw [Cont.eval, stepRet]; exact IH
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IH, bind_pure_comp]
  case cons₂ ns k IH => 

Proof state:
ns : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v : List ℕ
⊢ eval step (stepRet (Cont.cons₂ ns k) v) = Cfg.halt <$> Cont.eval (Cont.cons₂ ns k) v

Next tactic:
rw [Cont.eval, stepRet]
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IH, bind_pure_comp]
  case cons₂ ns k IH => rw [Cont.eval, stepRet]; 

Proof state:
ns : List ℕ
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v : List ℕ
⊢ eval step (stepRet k (List.headI ns :: v)) = Cfg.halt <$> (fun v => Cont.eval k (List.headI ns :: v)) v

Next tactic:
exact IH
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IH, bind_pure_comp]
  case cons₂ ns k IH => rw [Cont.eval, stepRet]; exact IH
  

Proof state:
case comp
a✝¹ : Code
a✝ : Cont
a_ih✝ : ∀ {v : List ℕ}, eval step (stepRet a✝ v) = Cfg.halt <$> Cont.eval a✝ v
v : List ℕ
⊢ eval step (stepRet (Cont.comp a✝¹ a✝) v) = Cfg.halt <$> Cont.eval (Cont.comp a✝¹ a✝) v
case fix
a✝¹ : Code
a✝ : Cont
a_ih✝ : ∀ {v : List ℕ}, eval step (stepRet a✝ v) = Cfg.halt <$> Cont.eval a✝ v
v : List ℕ
⊢ eval step (stepRet (Cont.fix a✝¹ a✝) v) = Cfg.halt <$> Cont.eval (Cont.fix a✝¹ a✝) v

Next tactic:
case comp f k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [IH, bind_pure_comp]
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IH, bind_pure_comp]
  case cons₂ ns k IH => rw [Cont.eval, stepRet]; exact IH
  

Proof state:
f : Code
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v : List ℕ
⊢ eval step (stepRet (Cont.comp f k) v) = Cfg.halt <$> Cont.eval (Cont.comp f k) v

Next tactic:
case comp f k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [IH, bind_pure_comp]
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IH, bind_pure_comp]
  case cons₂ ns k IH => rw [Cont.eval, stepRet]; exact IH
  case comp f k IH =>
    

Proof state:
f : Code
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v : List ℕ
⊢ eval step (stepRet (Cont.comp f k) v) = Cfg.halt <$> Cont.eval (Cont.comp f k) v

Next tactic:
rw [Cont.eval, stepRet, code_is_ok]
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IH, bind_pure_comp]
  case cons₂ ns k IH => rw [Cont.eval, stepRet]; exact IH
  case comp f k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    

Proof state:
f : Code
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v : List ℕ
⊢ (do
      let v ← Code.eval f v
      eval step (Cfg.ret k v)) =
    Cfg.halt <$> (fun v => Code.eval f v >>= Cont.eval k) v

Next tactic:
simp only [← bind_pure_comp, bind_assoc]
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IH, bind_pure_comp]
  case cons₂ ns k IH => rw [Cont.eval, stepRet]; exact IH
  case comp f k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; 

Proof state:
f : Code
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v : List ℕ
⊢ (do
      let v ← Code.eval f v
      eval step (Cfg.ret k v)) =
    do
    let x ← Code.eval f v
    let a ← Cont.eval k x
    pure (Cfg.halt a)

Next tactic:
congr
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IH, bind_pure_comp]
  case cons₂ ns k IH => rw [Cont.eval, stepRet]; exact IH
  case comp f k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; 

Proof state:
case e_a
f : Code
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v : List ℕ
⊢ (fun v => eval step (Cfg.ret k v)) = fun x => do
    let a ← Cont.eval k x
    pure (Cfg.halt a)

Next tactic:
funext v'
theorem stepRet_eval {k v} : eval step (stepRet k v) = Cfg.halt <$> k.eval v := by
  induction k generalizing v
  case halt =>
    simp only [mem_eval, Cont.eval, map_pure]
    exact Part.eq_some_iff.2 (mem_eval.2 ⟨ReflTransGen.refl, rfl⟩)
  case cons₁ fs as k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IH, bind_pure_comp]
  case cons₂ ns k IH => rw [Cont.eval, stepRet]; exact IH
  case comp f k IH =>
    rw [Cont.eval, stepRet, code_is_ok]
    simp only [← bind_pure_comp, bind_assoc]; congr; funext v'
    

Proof state:
case e_a.h
f : Code
k : Cont
IH : ∀ {v : List ℕ}, eval step (stepRet k v) = Cfg.halt <$> Cont.eval k v
v v' : List ℕ
⊢ eval step (Cfg.ret k v') = do
    let a ← Cont.eval k v'
    pure (Cfg.halt a)

Next tactic:
rw [reaches_eval]