l3lab/ntp-mathlib huggingface dataset:
theorem eq_thinkN {s : Computation α} {a n} (h : Results s a n) : s = thinkN (pure a) n := by
  revert s
  induction' n with n IH <;> intro s <;> apply recOn s (fun a' => _) fun s => _ <;> intro a h
  · rw [← eq_of_pure_mem h.mem]
    rfl
  · cases' of_results_think h with n h
    cases h
    contradiction
  · 

Proof state:
α : Type u
β : Type v
γ : Type w
a✝ : α
n : ℕ
IH : ∀ {s : Computation α}, Results s a✝ n → s = thinkN (pure a✝) n
s : Computation α
a : α
h : Results (pure a) a✝ (Nat.succ n)
⊢ pure a = thinkN (pure a✝) (Nat.succ n)

Next tactic:
have := h.len_unique (results_pure _)
theorem eq_thinkN {s : Computation α} {a n} (h : Results s a n) : s = thinkN (pure a) n := by
  revert s
  induction' n with n IH <;> intro s <;> apply recOn s (fun a' => _) fun s => _ <;> intro a h
  · rw [← eq_of_pure_mem h.mem]
    rfl
  · cases' of_results_think h with n h
    cases h
    contradiction
  · have := h.len_unique (results_pure _)
    

Proof state:
α : Type u
β : Type v
γ : Type w
a✝ : α
n : ℕ
IH : ∀ {s : Computation α}, Results s a✝ n → s = thinkN (pure a✝) n
s : Computation α
a : α
h : Results (pure a) a✝ (Nat.succ n)
this : Nat.succ n = 0
⊢ pure a = thinkN (pure a✝) (Nat.succ n)

Next tactic:
contradiction
theorem eq_thinkN {s : Computation α} {a n} (h : Results s a n) : s = thinkN (pure a) n := by
  revert s
  induction' n with n IH <;> intro s <;> apply recOn s (fun a' => _) fun s => _ <;> intro a h
  · rw [← eq_of_pure_mem h.mem]
    rfl
  · cases' of_results_think h with n h
    cases h
    contradiction
  · have := h.len_unique (results_pure _)
    contradiction
  · 

Proof state:
α : Type u
β : Type v
γ : Type w
a✝ : α
n : ℕ
IH : ∀ {s : Computation α}, Results s a✝ n → s = thinkN (pure a✝) n
s a : Computation α
h : Results (think a) a✝ (Nat.succ n)
⊢ think a = thinkN (pure a✝) (Nat.succ n)

Next tactic:
rw [IH (results_think_iff.1 h)]
theorem eq_thinkN {s : Computation α} {a n} (h : Results s a n) : s = thinkN (pure a) n := by
  revert s
  induction' n with n IH <;> intro s <;> apply recOn s (fun a' => _) fun s => _ <;> intro a h
  · rw [← eq_of_pure_mem h.mem]
    rfl
  · cases' of_results_think h with n h
    cases h
    contradiction
  · have := h.len_unique (results_pure _)
    contradiction
  · rw [IH (results_think_iff.1 h)]
    

Proof state:
α : Type u
β : Type v
γ : Type w
a✝ : α
n : ℕ
IH : ∀ {s : Computation α}, Results s a✝ n → s = thinkN (pure a✝) n
s a : Computation α
h : Results (think a) a✝ (Nat.succ n)
⊢ think (thinkN (pure a✝) n) = thinkN (pure a✝) (Nat.succ n)

Next tactic:
rfl
/-- Recursor based on membership-/
def memRecOn {C : Computation α → Sort v} {a s} (M : a ∈ s) (h1 : C (pure a))
    (h2 : ∀ s, C s → C (think s)) : C s := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
C : Computation α → Sort v
a : α
s : Computation α
M : a ∈ s
h1 : C (pure a)
h2 : (s : Computation α) → C s → C (think s)
⊢ C s

Next tactic:
haveI T := terminates_of_mem M
/-- Recursor based on membership-/
def memRecOn {C : Computation α → Sort v} {a s} (M : a ∈ s) (h1 : C (pure a))
    (h2 : ∀ s, C s → C (think s)) : C s := by
  haveI T := terminates_of_mem M
  

Proof state:
α : Type u
β : Type v
γ : Type w
C : Computation α → Sort v
a : α
s : Computation α
M : a ∈ s
h1 : C (pure a)
h2 : (s : Computation α) → C s → C (think s)
T : Terminates s
⊢ C s

Next tactic:
rw [eq_thinkN' s, get_eq_of_mem s M]
/-- Recursor based on membership-/
def memRecOn {C : Computation α → Sort v} {a s} (M : a ∈ s) (h1 : C (pure a))
    (h2 : ∀ s, C s → C (think s)) : C s := by
  haveI T := terminates_of_mem M
  rw [eq_thinkN' s, get_eq_of_mem s M]
  

Proof state:
α : Type u
β : Type v
γ : Type w
C : Computation α → Sort v
a : α
s : Computation α
M : a ∈ s
h1 : C (pure a)
h2 : (s : Computation α) → C s → C (think s)
T : Terminates s
⊢ C (thinkN (pure a) (length s))

Next tactic:
generalize length s = n
/-- Recursor based on membership-/
def memRecOn {C : Computation α → Sort v} {a s} (M : a ∈ s) (h1 : C (pure a))
    (h2 : ∀ s, C s → C (think s)) : C s := by
  haveI T := terminates_of_mem M
  rw [eq_thinkN' s, get_eq_of_mem s M]
  generalize length s = n
  

Proof state:
α : Type u
β : Type v
γ : Type w
C : Computation α → Sort v
a : α
s : Computation α
M : a ∈ s
h1 : C (pure a)
h2 : (s : Computation α) → C s → C (think s)
T : Terminates s
n : ℕ
⊢ C (thinkN (pure a) n)

Next tactic:
induction' n with n IH
/-- Recursor based on membership-/
def memRecOn {C : Computation α → Sort v} {a s} (M : a ∈ s) (h1 : C (pure a))
    (h2 : ∀ s, C s → C (think s)) : C s := by
  haveI T := terminates_of_mem M
  rw [eq_thinkN' s, get_eq_of_mem s M]
  generalize length s = n
  induction' n with n IH; 

Proof state:
case zero
α : Type u
β : Type v
γ : Type w
C : Computation α → Sort v
a : α
s : Computation α
M : a ∈ s
h1 : C (pure a)
h2 : (s : Computation α) → C s → C (think s)
T : Terminates s
⊢ C (thinkN (pure a) Nat.zero)
case succ
α : Type u
β : Type v
γ : Type w
C : Computation α → Sort v
a : α
s : Computation α
M : a ∈ s
h1 : C (pure a)
h2 : (s : Computation α) → C s → C (think s)
T : Terminates s
n : ℕ
IH : C (thinkN (pure a) n)
⊢ C (thinkN (pure a) (Nat.succ n))

Next tactic:
exacts [h1, h2 _ IH]
/-- Map a function on the result of a computation. -/
def map (f : α → β) : Computation α → Computation β
  | ⟨s, al⟩ =>
    ⟨s.map fun o => Option.casesOn o none (some ∘ f), fun n b => by
      

Proof state:
α : Type u
β : Type v
γ : Type w
f : α → β
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
n : ℕ
b : β
⊢ Stream'.map (fun o => Option.casesOn o none (some ∘ f)) s n = some b →
    Stream'.map (fun o => Option.casesOn o none (some ∘ f)) s (n + 1) = some b

Next tactic:
dsimp [Stream'.map, Stream'.get]
/-- Map a function on the result of a computation. -/
def map (f : α → β) : Computation α → Computation β
  | ⟨s, al⟩ =>
    ⟨s.map fun o => Option.casesOn o none (some ∘ f), fun n b => by
      dsimp [Stream'.map, Stream'.get]
      

Proof state:
α : Type u
β : Type v
γ : Type w
f : α → β
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
n : ℕ
b : β
⊢ Option.rec none (fun val => some (f val)) (s n) = some b →
    Option.rec none (fun val => some (f val)) (s (n + 1)) = some b

Next tactic:
induction' e : s n with a
/-- Map a function on the result of a computation. -/
def map (f : α → β) : Computation α → Computation β
  | ⟨s, al⟩ =>
    ⟨s.map fun o => Option.casesOn o none (some ∘ f), fun n b => by
      dsimp [Stream'.map, Stream'.get]
      induction' e : s n with a <;> 

Proof state:
case none
α : Type u
β : Type v
γ : Type w
f : α → β
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
n : ℕ
b : β
e : s n = none
⊢ Option.rec none (fun val => some (f val)) none = some b →
    Option.rec none (fun val => some (f val)) (s (n + 1)) = some b

Next tactic:
intro h
/-- Map a function on the result of a computation. -/
def map (f : α → β) : Computation α → Computation β
  | ⟨s, al⟩ =>
    ⟨s.map fun o => Option.casesOn o none (some ∘ f), fun n b => by
      dsimp [Stream'.map, Stream'.get]
      induction' e : s n with a <;> 

Proof state:
case some
α : Type u
β : Type v
γ : Type w
f : α → β
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
n : ℕ
b : β
a : α
e : s n = some a
⊢ Option.rec none (fun val => some (f val)) (some a) = some b →
    Option.rec none (fun val => some (f val)) (s (n + 1)) = some b

Next tactic:
intro h
/-- Map a function on the result of a computation. -/
def map (f : α → β) : Computation α → Computation β
  | ⟨s, al⟩ =>
    ⟨s.map fun o => Option.casesOn o none (some ∘ f), fun n b => by
      dsimp [Stream'.map, Stream'.get]
      induction' e : s n with a <;> intro h
      · 

Proof state:
case none
α : Type u
β : Type v
γ : Type w
f : α → β
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
n : ℕ
b : β
e : s n = none
h : Option.rec none (fun val => some (f val)) none = some b
⊢ Option.rec none (fun val => some (f val)) (s (n + 1)) = some b

Next tactic:
contradiction
/-- Map a function on the result of a computation. -/
def map (f : α → β) : Computation α → Computation β
  | ⟨s, al⟩ =>
    ⟨s.map fun o => Option.casesOn o none (some ∘ f), fun n b => by
      dsimp [Stream'.map, Stream'.get]
      induction' e : s n with a <;> intro h
      · contradiction
      · 

Proof state:
case some
α : Type u
β : Type v
γ : Type w
f : α → β
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
n : ℕ
b : β
a : α
e : s n = some a
h : Option.rec none (fun val => some (f val)) (some a) = some b
⊢ Option.rec none (fun val => some (f val)) (s (n + 1)) = some b

Next tactic:
rw [al e]
/-- Map a function on the result of a computation. -/
def map (f : α → β) : Computation α → Computation β
  | ⟨s, al⟩ =>
    ⟨s.map fun o => Option.casesOn o none (some ∘ f), fun n b => by
      dsimp [Stream'.map, Stream'.get]
      induction' e : s n with a <;> intro h
      · contradiction
      · rw [al e]; 

Proof state:
case some
α : Type u
β : Type v
γ : Type w
f : α → β
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
n : ℕ
b : β
a : α
e : s n = some a
h : Option.rec none (fun val => some (f val)) (some a) = some b
⊢ Option.rec none (fun val => some (f val)) (some a) = some b

Next tactic:
exact h
@[simp]
theorem map_think (f : α → β) : ∀ s, map f (think s) = think (map f s)
  | ⟨s, al⟩ => by 

Proof state:
α : Type u
β : Type v
γ : Type w
f : α → β
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
⊢ map f (think { val := s, property := al }) = think (map f { val := s, property := al })

Next tactic:
apply Subtype.eq
@[simp]
theorem map_think (f : α → β) : ∀ s, map f (think s) = think (map f s)
  | ⟨s, al⟩ => by apply Subtype.eq; 

Proof state:
case a
α : Type u
β : Type v
γ : Type w
f : α → β
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
⊢ ↑(map f (think { val := s, property := al })) = ↑(think (map f { val := s, property := al }))

Next tactic:
dsimp [think, map]
@[simp]
theorem map_think (f : α → β) : ∀ s, map f (think s) = think (map f s)
  | ⟨s, al⟩ => by apply Subtype.eq; dsimp [think, map]; 

Proof state:
case a
α : Type u
β : Type v
γ : Type w
f : α → β
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
⊢ Stream'.map (fun o => Option.rec none (fun val => some (f val)) o) (Stream'.cons none s) =
    Stream'.cons none (Stream'.map (fun o => Option.rec none (fun val => some (f val)) o) s)

Next tactic:
rw [Stream'.map_cons]
@[simp]
theorem destruct_map (f : α → β) (s) : destruct (map f s) = lmap f (rmap (map f) (destruct s)) := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
f : α → β
s : Computation α
⊢ destruct (map f s) = lmap f (rmap (map f) (destruct s))

Next tactic:
apply s.recOn
@[simp]
theorem destruct_map (f : α → β) (s) : destruct (map f s) = lmap f (rmap (map f) (destruct s)) := by
  apply s.recOn <;> 

Proof state:
case h1
α : Type u
β : Type v
γ : Type w
f : α → β
s : Computation α
⊢ ∀ (a : α), destruct (map f (pure a)) = lmap f (rmap (map f) (destruct (pure a)))

Next tactic:
intro
@[simp]
theorem destruct_map (f : α → β) (s) : destruct (map f s) = lmap f (rmap (map f) (destruct s)) := by
  apply s.recOn <;> 

Proof state:
case h2
α : Type u
β : Type v
γ : Type w
f : α → β
s : Computation α
⊢ ∀ (s : Computation α), destruct (map f (think s)) = lmap f (rmap (map f) (destruct (think s)))

Next tactic:
intro
@[simp]
theorem destruct_map (f : α → β) (s) : destruct (map f s) = lmap f (rmap (map f) (destruct s)) := by
  apply s.recOn <;> intro <;> 

Proof state:
case h1
α : Type u
β : Type v
γ : Type w
f : α → β
s : Computation α
a✝ : α
⊢ destruct (map f (pure a✝)) = lmap f (rmap (map f) (destruct (pure a✝)))

Next tactic:
simp
@[simp]
theorem destruct_map (f : α → β) (s) : destruct (map f s) = lmap f (rmap (map f) (destruct s)) := by
  apply s.recOn <;> intro <;> 

Proof state:
case h2
α : Type u
β : Type v
γ : Type w
f : α → β
s s✝ : Computation α
⊢ destruct (map f (think s✝)) = lmap f (rmap (map f) (destruct (think s✝)))

Next tactic:
simp
@[simp]
theorem map_id : ∀ s : Computation α, map id s = s
  | ⟨f, al⟩ => by
    

Proof state:
α : Type u
β : Type v
γ : Type w
f : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, f n = some a → f (n + 1) = some a
⊢ map id { val := f, property := al } = { val := f, property := al }

Next tactic:
apply Subtype.eq
@[simp]
theorem map_id : ∀ s : Computation α, map id s = s
  | ⟨f, al⟩ => by
    apply Subtype.eq; 

Proof state:
case a
α : Type u
β : Type v
γ : Type w
f : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, f n = some a → f (n + 1) = some a
⊢ ↑(map id { val := f, property := al }) = ↑{ val := f, property := al }

Next tactic:
simp [map, Function.comp]
@[simp]
theorem map_id : ∀ s : Computation α, map id s = s
  | ⟨f, al⟩ => by
    apply Subtype.eq; simp [map, Function.comp]
    

Proof state:
case a
α : Type u
β : Type v
γ : Type w
f : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, f n = some a → f (n + 1) = some a
⊢ Stream'.map (fun o => Option.rec none (fun val => some val) o) f = f

Next tactic:
have e : @Option.rec α (fun _ => Option α) none some = id := by ext ⟨⟩ <;> rfl
@[simp]
theorem map_id : ∀ s : Computation α, map id s = s
  | ⟨f, al⟩ => by
    apply Subtype.eq; simp [map, Function.comp]
    have e : @Option.rec α (fun _ => Option α) none some = id := by 

Proof state:
α : Type u
β : Type v
γ : Type w
f : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, f n = some a → f (n + 1) = some a
⊢ Option.rec none some = id

Next tactic:
ext ⟨⟩
@[simp]
theorem map_id : ∀ s : Computation α, map id s = s
  | ⟨f, al⟩ => by
    apply Subtype.eq; simp [map, Function.comp]
    have e : @Option.rec α (fun _ => Option α) none some = id := by ext ⟨⟩ <;> 

Proof state:
case h.none.a
α : Type u
β : Type v
γ : Type w
f : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, f n = some a → f (n + 1) = some a
a✝ : α
⊢ a✝ ∈ Option.rec none some none ↔ a✝ ∈ id none

Next tactic:
rfl
@[simp]
theorem map_id : ∀ s : Computation α, map id s = s
  | ⟨f, al⟩ => by
    apply Subtype.eq; simp [map, Function.comp]
    have e : @Option.rec α (fun _ => Option α) none some = id := by ext ⟨⟩ <;> 

Proof state:
case h.some.a
α : Type u
β : Type v
γ : Type w
f : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, f n = some a → f (n + 1) = some a
val✝ a✝ : α
⊢ a✝ ∈ Option.rec none some (some val✝) ↔ a✝ ∈ id (some val✝)

Next tactic:
rfl
@[simp]
theorem map_id : ∀ s : Computation α, map id s = s
  | ⟨f, al⟩ => by
    apply Subtype.eq; simp [map, Function.comp]
    have e : @Option.rec α (fun _ => Option α) none some = id := by ext ⟨⟩ <;> rfl
    

Proof state:
case a
α : Type u
β : Type v
γ : Type w
f : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, f n = some a → f (n + 1) = some a
e : Option.rec none some = id
⊢ Stream'.map (fun o => Option.rec none (fun val => some val) o) f = f

Next tactic:
have h : ((fun x: Option α => x) = id) := rfl
@[simp]
theorem map_id : ∀ s : Computation α, map id s = s
  | ⟨f, al⟩ => by
    apply Subtype.eq; simp [map, Function.comp]
    have e : @Option.rec α (fun _ => Option α) none some = id := by ext ⟨⟩ <;> rfl
    have h : ((fun x: Option α => x) = id) := rfl
    

Proof state:
case a
α : Type u
β : Type v
γ : Type w
f : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, f n = some a → f (n + 1) = some a
e : Option.rec none some = id
h : (fun x => x) = id
⊢ Stream'.map (fun o => Option.rec none (fun val => some val) o) f = f

Next tactic:
simp [e, h, Stream'.map_id]
theorem map_comp (f : α → β) (g : β → γ) : ∀ s : Computation α, map (g ∘ f) s = map g (map f s)
  | ⟨s, al⟩ => by
    

Proof state:
α : Type u
β : Type v
γ : Type w
f : α → β
g : β → γ
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
⊢ map (g ∘ f) { val := s, property := al } = map g (map f { val := s, property := al })

Next tactic:
apply Subtype.eq
theorem map_comp (f : α → β) (g : β → γ) : ∀ s : Computation α, map (g ∘ f) s = map g (map f s)
  | ⟨s, al⟩ => by
    apply Subtype.eq; 

Proof state:
case a
α : Type u
β : Type v
γ : Type w
f : α → β
g : β → γ
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
⊢ ↑(map (g ∘ f) { val := s, property := al }) = ↑(map g (map f { val := s, property := al }))

Next tactic:
dsimp [map]
theorem map_comp (f : α → β) (g : β → γ) : ∀ s : Computation α, map (g ∘ f) s = map g (map f s)
  | ⟨s, al⟩ => by
    apply Subtype.eq; dsimp [map]
    

Proof state:
case a
α : Type u
β : Type v
γ : Type w
f : α → β
g : β → γ
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
⊢ Stream'.map (fun o => Option.rec none (fun val => some (g (f val))) o) s =
    Stream'.map
      ((fun o => Option.rec none (fun val => some (g val)) o) ∘ fun o => Option.rec none (fun val => some (f val)) o) s

Next tactic:
apply congr_arg fun f : _ → Option γ => Stream'.map f s
theorem map_comp (f : α → β) (g : β → γ) : ∀ s : Computation α, map (g ∘ f) s = map g (map f s)
  | ⟨s, al⟩ => by
    apply Subtype.eq; dsimp [map]
    apply congr_arg fun f : _ → Option γ => Stream'.map f s
    

Proof state:
case a
α : Type u
β : Type v
γ : Type w
f : α → β
g : β → γ
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
⊢ (fun o => Option.rec none (fun val => some (g (f val))) o) =
    (fun o => Option.rec none (fun val => some (g val)) o) ∘ fun o => Option.rec none (fun val => some (f val)) o

Next tactic:
ext ⟨⟩
theorem map_comp (f : α → β) (g : β → γ) : ∀ s : Computation α, map (g ∘ f) s = map g (map f s)
  | ⟨s, al⟩ => by
    apply Subtype.eq; dsimp [map]
    apply congr_arg fun f : _ → Option γ => Stream'.map f s
    ext ⟨⟩ <;> 

Proof state:
case a.h.none.a
α : Type u
β : Type v
γ : Type w
f : α → β
g : β → γ
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
a✝ : γ
⊢ a✝ ∈ Option.rec none (fun val => some (g (f val))) none ↔
    a✝ ∈
      ((fun o => Option.rec none (fun val => some (g val)) o) ∘ fun o => Option.rec none (fun val => some (f val)) o)
        none

Next tactic:
rfl
theorem map_comp (f : α → β) (g : β → γ) : ∀ s : Computation α, map (g ∘ f) s = map g (map f s)
  | ⟨s, al⟩ => by
    apply Subtype.eq; dsimp [map]
    apply congr_arg fun f : _ → Option γ => Stream'.map f s
    ext ⟨⟩ <;> 

Proof state:
case a.h.some.a
α : Type u
β : Type v
γ : Type w
f : α → β
g : β → γ
s : Stream' (Option α)
al : ∀ ⦃n : ℕ⦄ ⦃a : α⦄, s n = some a → s (n + 1) = some a
val✝ : α
a✝ : γ
⊢ a✝ ∈ Option.rec none (fun val => some (g (f val))) (some val✝) ↔
    a✝ ∈
      ((fun o => Option.rec none (fun val => some (g val)) o) ∘ fun o => Option.rec none (fun val => some (f val)) o)
        (some val✝)

Next tactic:
rfl
@[simp]
theorem ret_bind (a) (f : α → Computation β) : bind (pure a) f = f a := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
a : α
f : α → Computation β
⊢ bind (pure a) f = f a

Next tactic:
apply
    eq_of_bisim fun c₁ c₂ => c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)
@[simp]
theorem ret_bind (a) (f : α → Computation β) : bind (pure a) f = f a := by
  apply
    eq_of_bisim fun c₁ c₂ => c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)
  · 

Proof state:
case bisim
α : Type u
β : Type v
γ : Type w
a : α
f : α → Computation β
⊢ IsBisimulation fun c₁ c₂ => c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)

Next tactic:
intro c₁ c₂ h
@[simp]
theorem ret_bind (a) (f : α → Computation β) : bind (pure a) f = f a := by
  apply
    eq_of_bisim fun c₁ c₂ => c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)
  · intro c₁ c₂ h
    

Proof state:
case bisim
α : Type u
β : Type v
γ : Type w
a : α
f : α → Computation β
c₁ c₂ : Computation β
h : c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)
⊢ BisimO (fun c₁ c₂ => c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)) (destruct c₁) (destruct c₂)

Next tactic:
match c₁, c₂, h with
    | _, _, Or.inl ⟨rfl, rfl⟩ =>
      simp only [BisimO, bind, Bind.f, corec_eq, rmap, destruct_pure]
      cases' destruct (f a) with b cb <;> simp [Bind.g]
    | _, c, Or.inr rfl =>
      simp only [BisimO, Bind.f, corec_eq, rmap]
      cases' destruct c with b cb <;> simp [Bind.g]
@[simp]
theorem ret_bind (a) (f : α → Computation β) : bind (pure a) f = f a := by
  apply
    eq_of_bisim fun c₁ c₂ => c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, _, Or.inl ⟨rfl, rfl⟩ =>
      

Proof state:
α : Type u
β : Type v
γ : Type w
a : α
f : α → Computation β
c₁ c₂ : Computation β
h : c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)
⊢ BisimO (fun c₁ c₂ => c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂))
    (destruct (bind (pure a) f)) (destruct (f a))

Next tactic:
simp only [BisimO, bind, Bind.f, corec_eq, rmap, destruct_pure]
@[simp]
theorem ret_bind (a) (f : α → Computation β) : bind (pure a) f = f a := by
  apply
    eq_of_bisim fun c₁ c₂ => c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, _, Or.inl ⟨rfl, rfl⟩ =>
      simp only [BisimO, bind, Bind.f, corec_eq, rmap, destruct_pure]
      

Proof state:
α : Type u
β : Type v
γ : Type w
a : α
f : α → Computation β
c₁ c₂ : Computation β
h : c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)
⊢ match
    match Bind.g (destruct (f a)) with
    | Sum.inl a => Sum.inl a
    | Sum.inr b => Sum.inr (corec (Bind.f f) b),
    destruct (f a) with
  | Sum.inl a, Sum.inl a' => a = a'
  | Sum.inr s, Sum.inr s' => s = corec (Bind.f f) (Sum.inl (pure a)) ∧ s' = f a ∨ s = corec (Bind.f f) (Sum.inr s')
  | x, x_1 => False

Next tactic:
cases' destruct (f a) with b cb
@[simp]
theorem ret_bind (a) (f : α → Computation β) : bind (pure a) f = f a := by
  apply
    eq_of_bisim fun c₁ c₂ => c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, _, Or.inl ⟨rfl, rfl⟩ =>
      simp only [BisimO, bind, Bind.f, corec_eq, rmap, destruct_pure]
      cases' destruct (f a) with b cb <;> 

Proof state:
case inl
α : Type u
β : Type v
γ : Type w
a : α
f : α → Computation β
c₁ c₂ : Computation β
h : c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)
b : β
⊢ match
    match Bind.g (Sum.inl b) with
    | Sum.inl a => Sum.inl a
    | Sum.inr b => Sum.inr (corec (Bind.f f) b),
    Sum.inl b with
  | Sum.inl a, Sum.inl a' => a = a'
  | Sum.inr s, Sum.inr s' => s = corec (Bind.f f) (Sum.inl (pure a)) ∧ s' = f a ∨ s = corec (Bind.f f) (Sum.inr s')
  | x, x_1 => False

Next tactic:
simp [Bind.g]
@[simp]
theorem ret_bind (a) (f : α → Computation β) : bind (pure a) f = f a := by
  apply
    eq_of_bisim fun c₁ c₂ => c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, _, Or.inl ⟨rfl, rfl⟩ =>
      simp only [BisimO, bind, Bind.f, corec_eq, rmap, destruct_pure]
      cases' destruct (f a) with b cb <;> 

Proof state:
case inr
α : Type u
β : Type v
γ : Type w
a : α
f : α → Computation β
c₁ c₂ : Computation β
h : c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)
cb : Computation β
⊢ match
    match Bind.g (Sum.inr cb) with
    | Sum.inl a => Sum.inl a
    | Sum.inr b => Sum.inr (corec (Bind.f f) b),
    Sum.inr cb with
  | Sum.inl a, Sum.inl a' => a = a'
  | Sum.inr s, Sum.inr s' => s = corec (Bind.f f) (Sum.inl (pure a)) ∧ s' = f a ∨ s = corec (Bind.f f) (Sum.inr s')
  | x, x_1 => False

Next tactic:
simp [Bind.g]
@[simp]
theorem ret_bind (a) (f : α → Computation β) : bind (pure a) f = f a := by
  apply
    eq_of_bisim fun c₁ c₂ => c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, _, Or.inl ⟨rfl, rfl⟩ =>
      simp only [BisimO, bind, Bind.f, corec_eq, rmap, destruct_pure]
      cases' destruct (f a) with b cb <;> simp [Bind.g]
    | _, c, Or.inr rfl =>
      

Proof state:
α : Type u
β : Type v
γ : Type w
a : α
f : α → Computation β
c₁ c₂ : Computation β
h : c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂)
c : Computation β
⊢ BisimO (fun c₁ c₂ => c₁ = bind (pure a) f ∧ c₂ = f a ∨ c₁ = corec (Bind.f f) (Sum.inr c₂))
    (destruct (corec (Bind.f f) (Sum.inr c))) (destruct c)

Next tactic:
simp only [BisimO, Bind.f, corec_eq, rmap]