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
    

Proof state:
case e_a.h
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v✝ v : List ℕ
⊢ eval step (stepRet (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 [stepRet, IHfs]
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]; 

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

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; funext v
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IHfs]; congr; 

Proof state:
case e_a.h.e_a
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v✝ v : List ℕ
⊢ (fun v_1 => eval step (Cfg.ret (Cont.cons₂ v k) v_1)) = fun x => eval step (Cfg.ret k (List.headI v :: x))

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
    rw [reaches_eval]; swap; exact ReflTransGen.single rfl
    rw [stepRet, IHfs]; congr; funext v'
    

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

Next tactic:
refine' Eq.trans _ (Eq.symm _)
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 _) <;> 

Proof state:
case e_a.h.e_a.h.refine'_1
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v✝ v v' : List ℕ
⊢ eval step (Cfg.ret (Cont.cons₂ v k) v') = ?e_a.h.e_a.h.refine'_2✝

Next tactic:
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 =>
    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 

Proof state:
case e_a.h.e_a.h.refine'_1
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v✝ v v' : List ℕ
⊢ eval step (Cfg.ret (Cont.cons₂ v k) v') = ?e_a.h.e_a.h.refine'_2✝

Next tactic:
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 =>
    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 _) <;> 

Proof state:
case e_a.h.e_a.h.refine'_3
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v✝ v v' : List ℕ
⊢ eval step (Cfg.ret k (List.headI v :: v')) = eval step (stepRet (Cont.cons₂ v k) v')

Next tactic:
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 =>
    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 

Proof state:
case e_a.h.e_a.h.refine'_3
f fs : Code
IHf : Code.Ok f
IHfs : Code.Ok fs
k : Cont
v✝ v v' : List ℕ
⊢ eval step (Cfg.ret k (List.headI v :: v')) = eval step (stepRet (Cont.cons₂ v k) v')

Next tactic:
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 =>
    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)
  

Proof state:
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 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]
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)
  

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

Next tactic:
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]
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 =>
    

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

Next tactic:
rw [Code.eval, IHg]
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]
    

Proof state:
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v : List ℕ
⊢ (do
      let v ← Code.eval g v
      eval step (Cfg.ret (Cont.comp f k) v)) =
    do
    let v ← (fun v => Code.eval g v >>= Code.eval f) 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]; 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]; 

Proof state:
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v : List ℕ
⊢ (do
      let v ← Code.eval g v
      eval step (Cfg.ret (Cont.comp f k) v)) =
    do
    let x ← Code.eval g v
    let v ← Code.eval f x
    eval step (Cfg.ret k v)

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; 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; 

Proof state:
case e_a
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v : List ℕ
⊢ (fun v => eval step (Cfg.ret (Cont.comp f k) v)) = fun x => do
    let v ← Code.eval f x
    eval step (Cfg.ret k v)

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
    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
    

Proof state:
case e_a.h
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v✝ v : List ℕ
⊢ eval step (Cfg.ret (Cont.comp f k) v) = do
    let v ← Code.eval f v
    eval step (Cfg.ret k v)

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]; 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]; 

Proof state:
case e_a.h
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v✝ v : List ℕ
⊢ eval step ?m.227339 = do
    let v ← Code.eval f v
    eval step (Cfg.ret k v)
case e_a.h
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v✝ v : List ℕ
⊢ Reaches step (Cfg.ret (Cont.comp f k) v) ?m.227339
f g : Code IHf : Code.Ok f IHg : Code.Ok g 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; 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; 

Proof state:
case e_a.h
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v✝ v : List ℕ
⊢ Reaches step (Cfg.ret (Cont.comp f k) v) ?m.227339
case e_a.h
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v✝ v : List ℕ
⊢ eval step ?m.227339 = do
    let v ← Code.eval f v
    eval step (Cfg.ret k v)
f g : Code IHf : Code.Ok f IHg : Code.Ok g k : Cont v✝ v : List ℕ ⊢ Cfg

Next tactic:
exact 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 =>
    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
    

Proof state:
case e_a.h
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v✝ v : List ℕ
⊢ eval step (stepRet (Cont.comp f k) v) = do
    let v ← Code.eval f v
    eval step (Cfg.ret k v)

Next tactic:
rw [stepRet, 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]
  

Proof state:
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 case f g IHf IHg =>
    simp only [Code.eval]
    cases v.headI <;> simp only [Code.eval] <;> [apply IHf; apply IHg]
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]
  

Proof state:
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v : List ℕ
⊢ eval step
      ((fun k v => Nat.rec (stepNormal f k (List.tail v)) (fun y x => stepNormal g k (y :: List.tail v)) (List.headI v))
        k v) =
    do
    let v ← Code.eval (Code.case f g) v
    eval step (Cfg.ret k v)

Next tactic:
case case f g IHf IHg =>
    simp only [Code.eval]
    cases v.headI <;> simp only [Code.eval] <;> [apply IHf; apply IHg]
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 =>
    

Proof state:
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v : List ℕ
⊢ eval step
      ((fun k v => Nat.rec (stepNormal f k (List.tail v)) (fun y x => stepNormal g k (y :: List.tail v)) (List.headI v))
        k v) =
    do
    let v ← Code.eval (Code.case f g) v
    eval step (Cfg.ret k v)

Next tactic:
simp only [Code.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]; 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]
    

Proof state:
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v : List ℕ
⊢ eval step (Nat.rec (stepNormal f k (List.tail v)) (fun y x => stepNormal g k (y :: List.tail v)) (List.headI v)) = do
    let v ← Nat.rec (Code.eval f (List.tail v)) (fun y x => Code.eval g (y :: List.tail v)) (List.headI v)
    eval step (Cfg.ret k v)

Next tactic:
cases v.headI <;> simp only [Code.eval] <;> [apply IHf; apply IHg]
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]
    

Proof state:
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v : List ℕ
⊢ eval step (Nat.rec (stepNormal f k (List.tail v)) (fun y x => stepNormal g k (y :: List.tail v)) (List.headI v)) = do
    let v ← Nat.rec (Code.eval f (List.tail v)) (fun y x => Code.eval g (y :: List.tail v)) (List.headI v)
    eval step (Cfg.ret k v)

Next tactic:
cases v.headI
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 <;> 

Proof state:
case zero
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v : List ℕ
⊢ eval step (Nat.rec (stepNormal f k (List.tail v)) (fun y x => stepNormal g k (y :: List.tail v)) Nat.zero) = do
    let v ← Nat.rec (Code.eval f (List.tail v)) (fun y x => Code.eval g (y :: List.tail v)) Nat.zero
    eval step (Cfg.ret k v)

Next tactic:
simp only [Code.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]; 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 <;> 

Proof state:
case succ
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v : List ℕ
n✝ : ℕ
⊢ eval step (Nat.rec (stepNormal f k (List.tail v)) (fun y x => stepNormal g k (y :: List.tail v)) (Nat.succ n✝)) = do
    let v ← Nat.rec (Code.eval f (List.tail v)) (fun y x => Code.eval g (y :: List.tail v)) (Nat.succ n✝)
    eval step (Cfg.ret k v)

Next tactic:
simp only [Code.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]; 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] <;> [

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

Next tactic:
apply 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; 

Proof state:
case succ
f g : Code
IHf : Code.Ok f
IHg : Code.Ok g
k : Cont
v : List ℕ
n✝ : ℕ
⊢ eval step (stepNormal g k (n✝ :: List.tail v)) = do
    let v ← Code.eval g (n✝ :: List.tail v)
    eval step (Cfg.ret k v)

Next tactic:
apply IHg