l3lab/ntp-mathlib huggingface dataset:
@[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 =>
      simp only [BisimO, Bind.f, corec_eq, rmap]
      

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 β
⊢ match
    match Bind.g (destruct c) with
    | Sum.inl a => Sum.inl a
    | Sum.inr b => Sum.inr (corec (Bind.f f) b),
    destruct c with
  | Sum.inl a, Sum.inl a' => a = a'
  | Sum.inr s, Sum.inr s' => s = bind (pure a) f ∧ s' = f a ∨ s = corec (Bind.f f) (Sum.inr s')
  | x, x_1 => False

Next tactic:
cases' destruct c 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 <;> simp [Bind.g]
    | _, c, Or.inr rfl =>
      simp only [BisimO, Bind.f, corec_eq, rmap]
      cases' destruct c 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₂)
c : Computation β
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 = bind (pure a) f ∧ 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 =>
      simp only [BisimO, Bind.f, corec_eq, rmap]
      cases' destruct c 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₂)
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 = bind (pure a) f ∧ 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 =>
      simp only [BisimO, Bind.f, corec_eq, rmap]
      cases' destruct c with b cb <;> simp [Bind.g]
  · 

Proof state:
case r
α : Type u
β : Type v
γ : Type w
a : α
f : α → Computation β
⊢ bind (pure a) f = bind (pure a) f ∧ f a = f a ∨ bind (pure a) f = corec (Bind.f f) (Sum.inr (f a))

Next tactic:
simp
@[simp]
theorem think_bind (c) (f : α → Computation β) : bind (think c) f = think (bind c f) :=
  destruct_eq_think <| by 

Proof state:
α : Type u
β : Type v
γ : Type w
c : Computation α
f : α → Computation β
⊢ destruct (bind (think c) f) = Sum.inr (bind c f)

Next tactic:
simp [bind, Bind.f]
@[simp]
theorem bind_pure (f : α → β) (s) : bind s (pure ∘ f) = map f s := by
  

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

Next tactic:
apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
@[simp]
theorem bind_pure (f : α → β) (s) : bind s (pure ∘ f) = map f s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
  · 

Proof state:
case bisim
α : Type u
β : Type v
γ : Type w
f : α → β
s : Computation α
⊢ IsBisimulation fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s

Next tactic:
intro c₁ c₂ h
@[simp]
theorem bind_pure (f : α → β) (s) : bind s (pure ∘ f) = map f s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
  · intro c₁ c₂ h
    

Proof state:
case bisim
α : Type u
β : Type v
γ : Type w
f : α → β
s : Computation α
c₁ c₂ : Computation β
h : c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s) (destruct c₁) (destruct c₂)

Next tactic:
match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      apply recOn s <;> intro s <;> simp
      exact Or.inr ⟨s, rfl, rfl⟩
@[simp]
theorem bind_pure (f : α → β) (s) : bind s (pure ∘ f) = map f s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => 

Proof state:
α : Type u
β : Type v
γ : Type w
f : α → β
s : Computation α
c₁ c₂✝ : Computation β
h : c₁ = c₂✝ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂✝ = map f s
c₂ : Computation β
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s) (destruct c₂) (destruct c₂)

Next tactic:
cases' destruct c₂ with b cb
@[simp]
theorem bind_pure (f : α → β) (s) : bind s (pure ∘ f) = map f s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> 

Proof state:
case inl
α : Type u
β : Type v
γ : Type w
f : α → β
s : Computation α
c₁ c₂✝ : Computation β
h : c₁ = c₂✝ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂✝ = map f s
c₂ : Computation β
b : β
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s) (Sum.inl b) (Sum.inl b)

Next tactic:
simp
@[simp]
theorem bind_pure (f : α → β) (s) : bind s (pure ∘ f) = map f s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> 

Proof state:
case inr
α : Type u
β : Type v
γ : Type w
f : α → β
s : Computation α
c₁ c₂✝ : Computation β
h : c₁ = c₂✝ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂✝ = map f s
c₂ cb : Computation β
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s) (Sum.inr cb) (Sum.inr cb)

Next tactic:
simp
@[simp]
theorem bind_pure (f : α → β) (s) : bind s (pure ∘ f) = map f s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      

Proof state:
α : Type u
β : Type v
γ : Type w
f : α → β
s✝ : Computation α
c₁ c₂ : Computation β
h : c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
s : Computation α
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s) (destruct (bind s (pure ∘ f)))
    (destruct (map f s))

Next tactic:
apply recOn s
@[simp]
theorem bind_pure (f : α → β) (s) : bind s (pure ∘ f) = map f s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      apply recOn s <;> 

Proof state:
case h1
α : Type u
β : Type v
γ : Type w
f : α → β
s✝ : Computation α
c₁ c₂ : Computation β
h : c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
s : Computation α
⊢ ∀ (a : α),
    BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s) (destruct (bind (pure a) (pure ∘ f)))
      (destruct (map f (pure a)))

Next tactic:
intro s
@[simp]
theorem bind_pure (f : α → β) (s) : bind s (pure ∘ f) = map f s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      apply recOn s <;> 

Proof state:
case h2
α : Type u
β : Type v
γ : Type w
f : α → β
s✝ : Computation α
c₁ c₂ : Computation β
h : c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
s : Computation α
⊢ ∀ (s : Computation α),
    BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s) (destruct (bind (think s) (pure ∘ f)))
      (destruct (map f (think s)))

Next tactic:
intro s
@[simp]
theorem bind_pure (f : α → β) (s) : bind s (pure ∘ f) = map f s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      apply recOn s <;> intro s <;> 

Proof state:
case h1
α : Type u
β : Type v
γ : Type w
f : α → β
s✝¹ : Computation α
c₁ c₂ : Computation β
h : c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
s✝ : Computation α
s : α
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s) (destruct (bind (pure s) (pure ∘ f)))
    (destruct (map f (pure s)))

Next tactic:
simp
@[simp]
theorem bind_pure (f : α → β) (s) : bind s (pure ∘ f) = map f s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      apply recOn s <;> intro s <;> 

Proof state:
case h2
α : Type u
β : Type v
γ : Type w
f : α → β
s✝¹ : Computation α
c₁ c₂ : Computation β
h : c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
s✝ s : Computation α
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s) (destruct (bind (think s) (pure ∘ f)))
    (destruct (map f (think s)))

Next tactic:
simp
@[simp]
theorem bind_pure (f : α → β) (s) : bind s (pure ∘ f) = map f s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      apply recOn s <;> intro s <;> simp
      

Proof state:
case h2
α : Type u
β : Type v
γ : Type w
f : α → β
s✝¹ : Computation α
c₁ c₂ : Computation β
h : c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
s✝ s : Computation α
⊢ bind s (pure ∘ f) = map f s ∨ ∃ s_1, bind s (pure ∘ f) = bind s_1 (pure ∘ f) ∧ map f s = map f s_1

Next tactic:
exact Or.inr ⟨s, rfl, rfl⟩
@[simp]
theorem bind_pure (f : α → β) (s) : bind s (pure ∘ f) = map f s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure ∘ f) ∧ c₂ = map f s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      apply recOn s <;> intro s <;> simp
      exact Or.inr ⟨s, rfl, rfl⟩
  · 

Proof state:
case r
α : Type u
β : Type v
γ : Type w
f : α → β
s : Computation α
⊢ bind s (pure ∘ f) = map f s ∨ ∃ s_1, bind s (pure ∘ f) = bind s_1 (pure ∘ f) ∧ map f s = map f s_1

Next tactic:
exact Or.inr ⟨s, rfl, rfl⟩
@[simp]
theorem bind_pure' (s : Computation α) : bind s pure = s := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
s : Computation α
⊢ bind s pure = s

Next tactic:
apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure) ∧ c₂ = s
@[simp]
theorem bind_pure' (s : Computation α) : bind s pure = s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure) ∧ c₂ = s
  · 

Proof state:
case bisim
α : Type u
β : Type v
γ : Type w
s : Computation α
⊢ IsBisimulation fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s

Next tactic:
intro c₁ c₂ h
@[simp]
theorem bind_pure' (s : Computation α) : bind s pure = s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure) ∧ c₂ = s
  · intro c₁ c₂ h
    

Proof state:
case bisim
α : Type u
β : Type v
γ : Type w
s c₁ c₂ : Computation α
h : c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s) (destruct c₁) (destruct c₂)

Next tactic:
match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      apply recOn s <;> intro s <;> simp
@[simp]
theorem bind_pure' (s : Computation α) : bind s pure = s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure) ∧ c₂ = s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => 

Proof state:
α : Type u
β : Type v
γ : Type w
s c₁ c₂✝ : Computation α
h : c₁ = c₂✝ ∨ ∃ s, c₁ = bind s pure ∧ c₂✝ = s
c₂ : Computation α
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s) (destruct c₂) (destruct c₂)

Next tactic:
cases' destruct c₂ with b cb
@[simp]
theorem bind_pure' (s : Computation α) : bind s pure = s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure) ∧ c₂ = s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> 

Proof state:
case inl
α : Type u
β : Type v
γ : Type w
s c₁ c₂✝ : Computation α
h : c₁ = c₂✝ ∨ ∃ s, c₁ = bind s pure ∧ c₂✝ = s
c₂ : Computation α
b : α
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s) (Sum.inl b) (Sum.inl b)

Next tactic:
simp
@[simp]
theorem bind_pure' (s : Computation α) : bind s pure = s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure) ∧ c₂ = s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> 

Proof state:
case inr
α : Type u
β : Type v
γ : Type w
s c₁ c₂✝ : Computation α
h : c₁ = c₂✝ ∨ ∃ s, c₁ = bind s pure ∧ c₂✝ = s
c₂ cb : Computation α
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s) (Sum.inr cb) (Sum.inr cb)

Next tactic:
simp
@[simp]
theorem bind_pure' (s : Computation α) : bind s pure = s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure) ∧ c₂ = s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      

Proof state:
α : Type u
β : Type v
γ : Type w
s✝ c₁ c₂ : Computation α
h : c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s
s : Computation α
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s) (destruct (bind s pure)) (destruct s)

Next tactic:
apply recOn s
@[simp]
theorem bind_pure' (s : Computation α) : bind s pure = s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure) ∧ c₂ = s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      apply recOn s <;> 

Proof state:
case h1
α : Type u
β : Type v
γ : Type w
s✝ c₁ c₂ : Computation α
h : c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s
s : Computation α
⊢ ∀ (a : α),
    BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s) (destruct (bind (pure a) pure)) (destruct (pure a))

Next tactic:
intro s
@[simp]
theorem bind_pure' (s : Computation α) : bind s pure = s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure) ∧ c₂ = s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      apply recOn s <;> 

Proof state:
case h2
α : Type u
β : Type v
γ : Type w
s✝ c₁ c₂ : Computation α
h : c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s
s : Computation α
⊢ ∀ (s : Computation α),
    BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s) (destruct (bind (think s) pure)) (destruct (think s))

Next tactic:
intro s
@[simp]
theorem bind_pure' (s : Computation α) : bind s pure = s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure) ∧ c₂ = s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      apply recOn s <;> intro s <;> 

Proof state:
case h1
α : Type u
β : Type v
γ : Type w
s✝¹ c₁ c₂ : Computation α
h : c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s
s✝ : Computation α
s : α
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s) (destruct (bind (pure s) pure)) (destruct (pure s))

Next tactic:
simp
@[simp]
theorem bind_pure' (s : Computation α) : bind s pure = s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure) ∧ c₂ = s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      apply recOn s <;> intro s <;> 

Proof state:
case h2
α : Type u
β : Type v
γ : Type w
s✝¹ c₁ c₂ : Computation α
h : c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s
s✝ s : Computation α
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s pure ∧ c₂ = s) (destruct (bind (think s) pure)) (destruct (think s))

Next tactic:
simp
@[simp]
theorem bind_pure' (s : Computation α) : bind s pure = s := by
  apply eq_of_bisim fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind s (pure) ∧ c₂ = s
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      apply recOn s <;> intro s <;> simp
  · 

Proof state:
case r
α : Type u
β : Type v
γ : Type w
s : Computation α
⊢ bind s pure = s ∨ ∃ s_1, bind s pure = bind s_1 pure ∧ s = s_1

Next tactic:
exact Or.inr ⟨s, rfl, rfl⟩
@[simp]
theorem bind_assoc (s : Computation α) (f : α → Computation β) (g : β → Computation γ) :
    bind (bind s f) g = bind s fun x : α => bind (f x) g := by
  

Proof state:
α : Type u
β : Type v
γ : Type w
s : Computation α
f : α → Computation β
g : β → Computation γ
⊢ bind (bind s f) g = bind s fun x => bind (f x) g

Next tactic:
apply
    eq_of_bisim fun c₁ c₂ =>
      c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x : α => bind (f x) g
@[simp]
theorem bind_assoc (s : Computation α) (f : α → Computation β) (g : β → Computation γ) :
    bind (bind s f) g = bind s fun x : α => bind (f x) g := by
  apply
    eq_of_bisim fun c₁ c₂ =>
      c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x : α => bind (f x) g
  · 

Proof state:
case bisim
α : Type u
β : Type v
γ : Type w
s : Computation α
f : α → Computation β
g : β → Computation γ
⊢ IsBisimulation fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x => bind (f x) g

Next tactic:
intro c₁ c₂ h
@[simp]
theorem bind_assoc (s : Computation α) (f : α → Computation β) (g : β → Computation γ) :
    bind (bind s f) g = bind s fun x : α => bind (f x) g := by
  apply
    eq_of_bisim fun c₁ c₂ =>
      c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x : α => bind (f x) g
  · intro c₁ c₂ h
    

Proof state:
case bisim
α : Type u
β : Type v
γ : Type w
s : Computation α
f : α → Computation β
g : β → Computation γ
c₁ c₂ : Computation γ
h : c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x => bind (f x) g
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x => bind (f x) g) (destruct c₁)
    (destruct c₂)

Next tactic:
match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      apply recOn s <;> intro s <;> simp
      · generalize f s = fs
        apply recOn fs <;> intro t <;> simp
        · cases' destruct (g t) with b cb <;> simp
      · exact Or.inr ⟨s, rfl, rfl⟩
@[simp]
theorem bind_assoc (s : Computation α) (f : α → Computation β) (g : β → Computation γ) :
    bind (bind s f) g = bind s fun x : α => bind (f x) g := by
  apply
    eq_of_bisim fun c₁ c₂ =>
      c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x : α => bind (f x) g
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => 

Proof state:
α : Type u
β : Type v
γ : Type w
s : Computation α
f : α → Computation β
g : β → Computation γ
c₁ c₂✝ : Computation γ
h : c₁ = c₂✝ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂✝ = bind s fun x => bind (f x) g
c₂ : Computation γ
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x => bind (f x) g) (destruct c₂)
    (destruct c₂)

Next tactic:
cases' destruct c₂ with b cb
@[simp]
theorem bind_assoc (s : Computation α) (f : α → Computation β) (g : β → Computation γ) :
    bind (bind s f) g = bind s fun x : α => bind (f x) g := by
  apply
    eq_of_bisim fun c₁ c₂ =>
      c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x : α => bind (f x) g
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> 

Proof state:
case inl
α : Type u
β : Type v
γ : Type w
s : Computation α
f : α → Computation β
g : β → Computation γ
c₁ c₂✝ : Computation γ
h : c₁ = c₂✝ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂✝ = bind s fun x => bind (f x) g
c₂ : Computation γ
b : γ
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x => bind (f x) g) (Sum.inl b)
    (Sum.inl b)

Next tactic:
simp
@[simp]
theorem bind_assoc (s : Computation α) (f : α → Computation β) (g : β → Computation γ) :
    bind (bind s f) g = bind s fun x : α => bind (f x) g := by
  apply
    eq_of_bisim fun c₁ c₂ =>
      c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x : α => bind (f x) g
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> 

Proof state:
case inr
α : Type u
β : Type v
γ : Type w
s : Computation α
f : α → Computation β
g : β → Computation γ
c₁ c₂✝ : Computation γ
h : c₁ = c₂✝ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂✝ = bind s fun x => bind (f x) g
c₂ cb : Computation γ
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x => bind (f x) g) (Sum.inr cb)
    (Sum.inr cb)

Next tactic:
simp
@[simp]
theorem bind_assoc (s : Computation α) (f : α → Computation β) (g : β → Computation γ) :
    bind (bind s f) g = bind s fun x : α => bind (f x) g := by
  apply
    eq_of_bisim fun c₁ c₂ =>
      c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x : α => bind (f x) g
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      

Proof state:
α : Type u
β : Type v
γ : Type w
s✝ : Computation α
f : α → Computation β
g : β → Computation γ
c₁ c₂ : Computation γ
h : c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x => bind (f x) g
s : Computation α
⊢ BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x => bind (f x) g)
    (destruct (bind (bind s f) g)) (destruct (bind s fun x => bind (f x) g))

Next tactic:
apply recOn s
@[simp]
theorem bind_assoc (s : Computation α) (f : α → Computation β) (g : β → Computation γ) :
    bind (bind s f) g = bind s fun x : α => bind (f x) g := by
  apply
    eq_of_bisim fun c₁ c₂ =>
      c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x : α => bind (f x) g
  · intro c₁ c₂ h
    match c₁, c₂, h with
    | _, c₂, Or.inl (Eq.refl _) => cases' destruct c₂ with b cb <;> simp
    | _, _, Or.inr ⟨s, rfl, rfl⟩ =>
      apply recOn s <;> 

Proof state:
case h1
α : Type u
β : Type v
γ : Type w
s✝ : Computation α
f : α → Computation β
g : β → Computation γ
c₁ c₂ : Computation γ
h : c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x => bind (f x) g
s : Computation α
⊢ ∀ (a : α),
    BisimO (fun c₁ c₂ => c₁ = c₂ ∨ ∃ s, c₁ = bind (bind s f) g ∧ c₂ = bind s fun x => bind (f x) g)
      (destruct (bind (bind (pure a) f) g)) (destruct (bind (pure a) fun x => bind (f x) g))

Next tactic:
intro s