l3lab/ntp-mathlib huggingface dataset:
theorem ofOption_eq_get {α} (o : Option α) : ofOption o = ⟨_, @Option.get _ o⟩ :=
  Part.ext' (ofOption_dom o) fun h₁ h₂ => by
    

Proof state:
α✝ : Type u_1
β : Type u_2
γ : Type u_3
α : Type u_4
o : Option α
h₁ : (↑o).Dom
h₂ : { Dom := Option.isSome o = true, get := Option.get o }.Dom
⊢ get (↑o) h₁ = get { Dom := Option.isSome o = true, get := Option.get o } h₂

Next tactic:
cases o
theorem ofOption_eq_get {α} (o : Option α) : ofOption o = ⟨_, @Option.get _ o⟩ :=
  Part.ext' (ofOption_dom o) fun h₁ h₂ => by
    cases o
    · 

Proof state:
case none
α✝ : Type u_1
β : Type u_2
γ : Type u_3
α : Type u_4
h₁ : (↑Option.none).Dom
h₂ : { Dom := Option.isSome Option.none = true, get := Option.get Option.none }.Dom
⊢ get (↑Option.none) h₁ = get { Dom := Option.isSome Option.none = true, get := Option.get Option.none } h₂

Next tactic:
simp at h₂
theorem ofOption_eq_get {α} (o : Option α) : ofOption o = ⟨_, @Option.get _ o⟩ :=
  Part.ext' (ofOption_dom o) fun h₁ h₂ => by
    cases o
    · simp at h₂
    · 

Proof state:
case some
α✝ : Type u_1
β : Type u_2
γ : Type u_3
α : Type u_4
val✝ : α
h₁ : (↑(Option.some val✝)).Dom
h₂ : { Dom := Option.isSome (Option.some val✝) = true, get := Option.get (Option.some val✝) }.Dom
⊢ get (↑(Option.some val✝)) h₁ =
    get { Dom := Option.isSome (Option.some val✝) = true, get := Option.get (Option.some val✝) } h₂

Next tactic:
rfl
@[simp]
theorem to_ofOption (o : Option α) : toOption (ofOption o) = o := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
o : Option α
⊢ toOption ↑o = o

Next tactic:
cases o
@[simp]
theorem to_ofOption (o : Option α) : toOption (ofOption o) = o := by cases o <;> 

Proof state:
case none
α : Type u_1
β : Type u_2
γ : Type u_3
⊢ toOption ↑Option.none = Option.none

Next tactic:
rfl
@[simp]
theorem to_ofOption (o : Option α) : toOption (ofOption o) = o := by cases o <;> 

Proof state:
case some
α : Type u_1
β : Type u_2
γ : Type u_3
val✝ : α
⊢ toOption ↑(Option.some val✝) = Option.some val✝

Next tactic:
rfl
/-- `Part α` is (classically) equivalent to `Option α`. -/
noncomputable def equivOption : Part α ≃ Option α :=
  haveI := Classical.dec
  ⟨fun o => toOption o, ofOption, fun o => of_toOption o, fun o =>
    Eq.trans (by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
this : (p : Prop) → Decidable p
o : Option α
⊢ (fun o => toOption o) ↑o = toOption ↑o

Next tactic:
dsimp
/-- `Part α` is (classically) equivalent to `Option α`. -/
noncomputable def equivOption : Part α ≃ Option α :=
  haveI := Classical.dec
  ⟨fun o => toOption o, ofOption, fun o => of_toOption o, fun o =>
    Eq.trans (by dsimp; 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
this : (p : Prop) → Decidable p
o : Option α
⊢ toOption ↑o = toOption ↑o

Next tactic:
congr
instance : OrderBot (Part α) where
  bot := none
  bot_le := by
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
⊢ ∀ (a : Part α), ⊥ ≤ a

Next tactic:
introv x
instance : OrderBot (Part α) where
  bot := none
  bot_le := by
    introv x
    

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
a : Part α
x : α
⊢ x ∈ ⊥ → x ∈ a

Next tactic:
rintro ⟨⟨_⟩, _⟩
theorem le_total_of_le_of_le {x y : Part α} (z : Part α) (hx : x ≤ z) (hy : y ≤ z) :
    x ≤ y ∨ y ≤ x := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
x y z : Part α
hx : x ≤ z
hy : y ≤ z
⊢ x ≤ y ∨ y ≤ x

Next tactic:
rcases Part.eq_none_or_eq_some x with (h | ⟨b, h₀⟩)
theorem le_total_of_le_of_le {x y : Part α} (z : Part α) (hx : x ≤ z) (hy : y ≤ z) :
    x ≤ y ∨ y ≤ x := by
  rcases Part.eq_none_or_eq_some x with (h | ⟨b, h₀⟩)
  · 

Proof state:
case inl
α : Type u_1
β : Type u_2
γ : Type u_3
x y z : Part α
hx : x ≤ z
hy : y ≤ z
h : x = none
⊢ x ≤ y ∨ y ≤ x

Next tactic:
rw [h]
theorem le_total_of_le_of_le {x y : Part α} (z : Part α) (hx : x ≤ z) (hy : y ≤ z) :
    x ≤ y ∨ y ≤ x := by
  rcases Part.eq_none_or_eq_some x with (h | ⟨b, h₀⟩)
  · rw [h]
    

Proof state:
case inl
α : Type u_1
β : Type u_2
γ : Type u_3
x y z : Part α
hx : x ≤ z
hy : y ≤ z
h : x = none
⊢ none ≤ y ∨ y ≤ none

Next tactic:
left
theorem le_total_of_le_of_le {x y : Part α} (z : Part α) (hx : x ≤ z) (hy : y ≤ z) :
    x ≤ y ∨ y ≤ x := by
  rcases Part.eq_none_or_eq_some x with (h | ⟨b, h₀⟩)
  · rw [h]
    left
    

Proof state:
case inl.h
α : Type u_1
β : Type u_2
γ : Type u_3
x y z : Part α
hx : x ≤ z
hy : y ≤ z
h : x = none
⊢ none ≤ y

Next tactic:
apply OrderBot.bot_le _
theorem le_total_of_le_of_le {x y : Part α} (z : Part α) (hx : x ≤ z) (hy : y ≤ z) :
    x ≤ y ∨ y ≤ x := by
  rcases Part.eq_none_or_eq_some x with (h | ⟨b, h₀⟩)
  · rw [h]
    left
    apply OrderBot.bot_le _
  

Proof state:
case inr.intro
α : Type u_1
β : Type u_2
γ : Type u_3
x y z : Part α
hx : x ≤ z
hy : y ≤ z
b : α
h₀ : x = some b
⊢ x ≤ y ∨ y ≤ x

Next tactic:
right
theorem le_total_of_le_of_le {x y : Part α} (z : Part α) (hx : x ≤ z) (hy : y ≤ z) :
    x ≤ y ∨ y ≤ x := by
  rcases Part.eq_none_or_eq_some x with (h | ⟨b, h₀⟩)
  · rw [h]
    left
    apply OrderBot.bot_le _
  right; 

Proof state:
case inr.intro.h
α : Type u_1
β : Type u_2
γ : Type u_3
x y z : Part α
hx : x ≤ z
hy : y ≤ z
b : α
h₀ : x = some b
⊢ y ≤ x

Next tactic:
intro b' h₁
theorem le_total_of_le_of_le {x y : Part α} (z : Part α) (hx : x ≤ z) (hy : y ≤ z) :
    x ≤ y ∨ y ≤ x := by
  rcases Part.eq_none_or_eq_some x with (h | ⟨b, h₀⟩)
  · rw [h]
    left
    apply OrderBot.bot_le _
  right; intro b' h₁
  

Proof state:
case inr.intro.h
α : Type u_1
β : Type u_2
γ : Type u_3
x y z : Part α
hx : x ≤ z
hy : y ≤ z
b : α
h₀ : x = some b
b' : α
h₁ : b' ∈ y
⊢ b' ∈ x

Next tactic:
rw [Part.eq_some_iff] at h₀
theorem le_total_of_le_of_le {x y : Part α} (z : Part α) (hx : x ≤ z) (hy : y ≤ z) :
    x ≤ y ∨ y ≤ x := by
  rcases Part.eq_none_or_eq_some x with (h | ⟨b, h₀⟩)
  · rw [h]
    left
    apply OrderBot.bot_le _
  right; intro b' h₁
  rw [Part.eq_some_iff] at h₀
  

Proof state:
case inr.intro.h
α : Type u_1
β : Type u_2
γ : Type u_3
x y z : Part α
hx : x ≤ z
hy : y ≤ z
b : α
h₀ : b ∈ x
b' : α
h₁ : b' ∈ y
⊢ b' ∈ x

Next tactic:
have hx := hx _ h₀
theorem le_total_of_le_of_le {x y : Part α} (z : Part α) (hx : x ≤ z) (hy : y ≤ z) :
    x ≤ y ∨ y ≤ x := by
  rcases Part.eq_none_or_eq_some x with (h | ⟨b, h₀⟩)
  · rw [h]
    left
    apply OrderBot.bot_le _
  right; intro b' h₁
  rw [Part.eq_some_iff] at h₀
  have hx := hx _ h₀; 

Proof state:
case inr.intro.h
α : Type u_1
β : Type u_2
γ : Type u_3
x y z : Part α
hx✝ : x ≤ z
hy : y ≤ z
b : α
h₀ : b ∈ x
b' : α
h₁ : b' ∈ y
hx : b ∈ z
⊢ b' ∈ x

Next tactic:
have hy := hy _ h₁
theorem le_total_of_le_of_le {x y : Part α} (z : Part α) (hx : x ≤ z) (hy : y ≤ z) :
    x ≤ y ∨ y ≤ x := by
  rcases Part.eq_none_or_eq_some x with (h | ⟨b, h₀⟩)
  · rw [h]
    left
    apply OrderBot.bot_le _
  right; intro b' h₁
  rw [Part.eq_some_iff] at h₀
  have hx := hx _ h₀; have hy := hy _ h₁
  

Proof state:
case inr.intro.h
α : Type u_1
β : Type u_2
γ : Type u_3
x y z : Part α
hx✝ : x ≤ z
hy✝ : y ≤ z
b : α
h₀ : b ∈ x
b' : α
h₁ : b' ∈ y
hx : b ∈ z
hy : b' ∈ z
⊢ b' ∈ x

Next tactic:
have hx := Part.mem_unique hx hy
theorem le_total_of_le_of_le {x y : Part α} (z : Part α) (hx : x ≤ z) (hy : y ≤ z) :
    x ≤ y ∨ y ≤ x := by
  rcases Part.eq_none_or_eq_some x with (h | ⟨b, h₀⟩)
  · rw [h]
    left
    apply OrderBot.bot_le _
  right; intro b' h₁
  rw [Part.eq_some_iff] at h₀
  have hx := hx _ h₀; have hy := hy _ h₁
  have hx := Part.mem_unique hx hy; 

Proof state:
case inr.intro.h
α : Type u_1
β : Type u_2
γ : Type u_3
x y z : Part α
hx✝¹ : x ≤ z
hy✝ : y ≤ z
b : α
h₀ : b ∈ x
b' : α
h₁ : b' ∈ y
hx✝ : b ∈ z
hy : b' ∈ z
hx : b = b'
⊢ b' ∈ x

Next tactic:
subst hx
theorem le_total_of_le_of_le {x y : Part α} (z : Part α) (hx : x ≤ z) (hy : y ≤ z) :
    x ≤ y ∨ y ≤ x := by
  rcases Part.eq_none_or_eq_some x with (h | ⟨b, h₀⟩)
  · rw [h]
    left
    apply OrderBot.bot_le _
  right; intro b' h₁
  rw [Part.eq_some_iff] at h₀
  have hx := hx _ h₀; have hy := hy _ h₁
  have hx := Part.mem_unique hx hy; subst hx
  

Proof state:
case inr.intro.h
α : Type u_1
β : Type u_2
γ : Type u_3
x y z : Part α
hx✝ : x ≤ z
hy✝ : y ≤ z
b : α
h₀ : b ∈ x
hx : b ∈ z
h₁ : b ∈ y
hy : b ∈ z
⊢ b ∈ x

Next tactic:
exact h₀
@[simp]
theorem map_none (f : α → β) : map f none = none :=
  eq_none_iff.2 fun a => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β
a : β
⊢ a ∉ map f none

Next tactic:
simp
theorem assert_pos {p : Prop} {f : p → Part α} (h : p) : assert p f = f h := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : Prop
f : p → Part α
h : p
⊢ assert p f = f h

Next tactic:
dsimp [assert]
theorem assert_pos {p : Prop} {f : p → Part α} (h : p) : assert p f = f h := by
  dsimp [assert]
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : Prop
f : p → Part α
h : p
⊢ { Dom := ∃ (h : p), (f h).Dom, get := fun ha => get (f (_ : p)) (_ : (f (_ : p)).Dom) } = f h

Next tactic:
cases h' : f h
theorem assert_pos {p : Prop} {f : p → Part α} (h : p) : assert p f = f h := by
  dsimp [assert]
  cases h' : f h
  

Proof state:
case mk
α : Type u_1
β : Type u_2
γ : Type u_3
p : Prop
f : p → Part α
h : p
Dom✝ : Prop
get✝ : Dom✝ → α
h' : f h = { Dom := Dom✝, get := get✝ }
⊢ { Dom := ∃ (h : p), (f h).Dom, get := fun ha => get (f (_ : p)) (_ : (f (_ : p)).Dom) } = { Dom := Dom✝, get := get✝ }

Next tactic:
simp only [h', mk.injEq, h, exists_prop_of_true, true_and]
theorem assert_pos {p : Prop} {f : p → Part α} (h : p) : assert p f = f h := by
  dsimp [assert]
  cases h' : f h
  simp only [h', mk.injEq, h, exists_prop_of_true, true_and]
  

Proof state:
case mk
α : Type u_1
β : Type u_2
γ : Type u_3
p : Prop
f : p → Part α
h : p
Dom✝ : Prop
get✝ : Dom✝ → α
h' : f h = { Dom := Dom✝, get := get✝ }
⊢ HEq (fun ha => get✝ (_ : { Dom := Dom✝, get := get✝ }.Dom)) get✝

Next tactic:
apply Function.hfunext
theorem assert_pos {p : Prop} {f : p → Part α} (h : p) : assert p f = f h := by
  dsimp [assert]
  cases h' : f h
  simp only [h', mk.injEq, h, exists_prop_of_true, true_and]
  apply Function.hfunext
  · 

Proof state:
case mk.hα
α : Type u_1
β : Type u_2
γ : Type u_3
p : Prop
f : p → Part α
h : p
Dom✝ : Prop
get✝ : Dom✝ → α
h' : f h = { Dom := Dom✝, get := get✝ }
⊢ (∃ (h : p), (f h).Dom) = Dom✝

Next tactic:
simp only [h, h', exists_prop_of_true]
theorem assert_pos {p : Prop} {f : p → Part α} (h : p) : assert p f = f h := by
  dsimp [assert]
  cases h' : f h
  simp only [h', mk.injEq, h, exists_prop_of_true, true_and]
  apply Function.hfunext
  · simp only [h, h', exists_prop_of_true]
  · 

Proof state:
case mk.h
α : Type u_1
β : Type u_2
γ : Type u_3
p : Prop
f : p → Part α
h : p
Dom✝ : Prop
get✝ : Dom✝ → α
h' : f h = { Dom := Dom✝, get := get✝ }
⊢ ∀ (a : ∃ (h : p), (f h).Dom) (a' : Dom✝), HEq a a' → HEq (get✝ (_ : { Dom := Dom✝, get := get✝ }.Dom)) (get✝ a')

Next tactic:
aesop
theorem assert_neg {p : Prop} {f : p → Part α} (h : ¬p) : assert p f = none := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : Prop
f : p → Part α
h : ¬p
⊢ assert p f = none

Next tactic:
dsimp [assert, none]
theorem assert_neg {p : Prop} {f : p → Part α} (h : ¬p) : assert p f = none := by
  dsimp [assert, none]; 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
p : Prop
f : p → Part α
h : ¬p
⊢ { Dom := ∃ (h : p), (f h).Dom, get := fun ha => get (f (_ : p)) (_ : (f (_ : p)).Dom) } =
    { Dom := False, get := fun t => False.rec (fun x => α) t }

Next tactic:
congr
theorem assert_neg {p : Prop} {f : p → Part α} (h : ¬p) : assert p f = none := by
  dsimp [assert, none]; congr
  · 

Proof state:
case h.e_2
α : Type u_1
β : Type u_2
γ : Type u_3
p : Prop
f : p → Part α
h : ¬p
⊢ (∃ (h : p), (f h).Dom) = False

Next tactic:
simp only [h, not_false_iff, exists_prop_of_false]
theorem assert_neg {p : Prop} {f : p → Part α} (h : ¬p) : assert p f = none := by
  dsimp [assert, none]; congr
  · simp only [h, not_false_iff, exists_prop_of_false]
  · 

Proof state:
case h.e_3
α : Type u_1
β : Type u_2
γ : Type u_3
p : Prop
f : p → Part α
h : ¬p
⊢ HEq (fun ha => get (f (_ : p)) (_ : (f (_ : p)).Dom)) fun t => False.rec (fun x => α) t

Next tactic:
apply Function.hfunext
theorem assert_neg {p : Prop} {f : p → Part α} (h : ¬p) : assert p f = none := by
  dsimp [assert, none]; congr
  · simp only [h, not_false_iff, exists_prop_of_false]
  · apply Function.hfunext
    · 

Proof state:
case h.e_3.hα
α : Type u_1
β : Type u_2
γ : Type u_3
p : Prop
f : p → Part α
h : ¬p
⊢ (∃ (h : p), (f h).Dom) = False

Next tactic:
simp only [h, not_false_iff, exists_prop_of_false]
theorem assert_neg {p : Prop} {f : p → Part α} (h : ¬p) : assert p f = none := by
  dsimp [assert, none]; congr
  · simp only [h, not_false_iff, exists_prop_of_false]
  · apply Function.hfunext
    · simp only [h, not_false_iff, exists_prop_of_false]
    

Proof state:
case h.e_3.h
α : Type u_1
β : Type u_2
γ : Type u_3
p : Prop
f : p → Part α
h : ¬p
⊢ ∀ (a : ∃ (h : p), (f h).Dom) (a' : False),
    HEq a a' → HEq (get (f (_ : p)) (_ : (f (_ : p)).Dom)) (False.rec (fun x => α) a')

Next tactic:
simp at *
protected theorem Dom.bind {o : Part α} (h : o.Dom) (f : α → Part β) : o.bind f = f (o.get h) := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
o : Part α
h : o.Dom
f : α → Part β
⊢ Part.bind o f = f (get o h)

Next tactic:
ext b
protected theorem Dom.bind {o : Part α} (h : o.Dom) (f : α → Part β) : o.bind f = f (o.get h) := by
  ext b
  

Proof state:
case H
α : Type u_1
β : Type u_2
γ : Type u_3
o : Part α
h : o.Dom
f : α → Part β
b : β
⊢ b ∈ Part.bind o f ↔ b ∈ f (get o h)

Next tactic:
simp only [Part.mem_bind_iff, exists_prop]
protected theorem Dom.bind {o : Part α} (h : o.Dom) (f : α → Part β) : o.bind f = f (o.get h) := by
  ext b
  simp only [Part.mem_bind_iff, exists_prop]
  

Proof state:
case H
α : Type u_1
β : Type u_2
γ : Type u_3
o : Part α
h : o.Dom
f : α → Part β
b : β
⊢ (∃ a ∈ o, b ∈ f a) ↔ b ∈ f (get o h)

Next tactic:
refine' ⟨_, fun hb => ⟨o.get h, Part.get_mem _, hb⟩⟩
protected theorem Dom.bind {o : Part α} (h : o.Dom) (f : α → Part β) : o.bind f = f (o.get h) := by
  ext b
  simp only [Part.mem_bind_iff, exists_prop]
  refine' ⟨_, fun hb => ⟨o.get h, Part.get_mem _, hb⟩⟩
  

Proof state:
case H
α : Type u_1
β : Type u_2
γ : Type u_3
o : Part α
h : o.Dom
f : α → Part β
b : β
⊢ (∃ a ∈ o, b ∈ f a) → b ∈ f (get o h)

Next tactic:
rintro ⟨a, ha, hb⟩
protected theorem Dom.bind {o : Part α} (h : o.Dom) (f : α → Part β) : o.bind f = f (o.get h) := by
  ext b
  simp only [Part.mem_bind_iff, exists_prop]
  refine' ⟨_, fun hb => ⟨o.get h, Part.get_mem _, hb⟩⟩
  rintro ⟨a, ha, hb⟩
  

Proof state:
case H.intro.intro
α : Type u_1
β : Type u_2
γ : Type u_3
o : Part α
h : o.Dom
f : α → Part β
b : β
a : α
ha : a ∈ o
hb : b ∈ f a
⊢ b ∈ f (get o h)

Next tactic:
rwa [Part.get_eq_of_mem ha]
@[simp]
theorem bind_none (f : α → Part β) : none.bind f = none :=
  eq_none_iff.2 fun a => by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → Part β
a : β
⊢ a ∉ Part.bind none f

Next tactic:
simp
@[simp]
theorem bind_some (a : α) (f : α → Part β) : (some a).bind f = f a :=
  ext <| by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
a : α
f : α → Part β
⊢ ∀ (a_1 : β), a_1 ∈ Part.bind (some a) f ↔ a_1 ∈ f a

Next tactic:
simp
theorem bind_of_mem {o : Part α} {a : α} (h : a ∈ o) (f : α → Part β) : o.bind f = f a := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
o : Part α
a : α
h : a ∈ o
f : α → Part β
⊢ Part.bind o f = f a

Next tactic:
rw [eq_some_iff.2 h, bind_some]
theorem bind_some_eq_map (f : α → β) (x : Part α) : x.bind (some ∘ f) = map f x :=
  ext <| by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → β
x : Part α
⊢ ∀ (a : β), a ∈ Part.bind x (some ∘ f) ↔ a ∈ map f x

Next tactic:
simp [eq_comm]
theorem bind_toOption (f : α → Part β) (o : Part α) [Decidable o.Dom] [∀ a, Decidable (f a).Dom]
    [Decidable (o.bind f).Dom] :
    (o.bind f).toOption = o.toOption.elim Option.none fun a => (f a).toOption := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → Part β
o : Part α
inst✝² : Decidable o.Dom
inst✝¹ : (a : α) → Decidable (f a).Dom
inst✝ : Decidable (Part.bind o f).Dom
⊢ toOption (Part.bind o f) = Option.elim (toOption o) Option.none fun a => toOption (f a)

Next tactic:
by_cases h : o.Dom
theorem bind_toOption (f : α → Part β) (o : Part α) [Decidable o.Dom] [∀ a, Decidable (f a).Dom]
    [Decidable (o.bind f).Dom] :
    (o.bind f).toOption = o.toOption.elim Option.none fun a => (f a).toOption := by
  by_cases h : o.Dom
  · 

Proof state:
case pos
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → Part β
o : Part α
inst✝² : Decidable o.Dom
inst✝¹ : (a : α) → Decidable (f a).Dom
inst✝ : Decidable (Part.bind o f).Dom
h : o.Dom
⊢ toOption (Part.bind o f) = Option.elim (toOption o) Option.none fun a => toOption (f a)

Next tactic:
simp_rw [h.toOption, h.bind]
theorem bind_toOption (f : α → Part β) (o : Part α) [Decidable o.Dom] [∀ a, Decidable (f a).Dom]
    [Decidable (o.bind f).Dom] :
    (o.bind f).toOption = o.toOption.elim Option.none fun a => (f a).toOption := by
  by_cases h : o.Dom
  · simp_rw [h.toOption, h.bind]
    

Proof state:
case pos
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → Part β
o : Part α
inst✝² : Decidable o.Dom
inst✝¹ : (a : α) → Decidable (f a).Dom
inst✝ : Decidable (Part.bind o f).Dom
h : o.Dom
⊢ toOption (f (get o h)) = Option.elim (Option.some (get o h)) Option.none fun a => toOption (f a)

Next tactic:
rfl
theorem bind_toOption (f : α → Part β) (o : Part α) [Decidable o.Dom] [∀ a, Decidable (f a).Dom]
    [Decidable (o.bind f).Dom] :
    (o.bind f).toOption = o.toOption.elim Option.none fun a => (f a).toOption := by
  by_cases h : o.Dom
  · simp_rw [h.toOption, h.bind]
    rfl
  · 

Proof state:
case neg
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → Part β
o : Part α
inst✝² : Decidable o.Dom
inst✝¹ : (a : α) → Decidable (f a).Dom
inst✝ : Decidable (Part.bind o f).Dom
h : ¬o.Dom
⊢ toOption (Part.bind o f) = Option.elim (toOption o) Option.none fun a => toOption (f a)

Next tactic:
rw [Part.toOption_eq_none_iff.2 h]
theorem bind_toOption (f : α → Part β) (o : Part α) [Decidable o.Dom] [∀ a, Decidable (f a).Dom]
    [Decidable (o.bind f).Dom] :
    (o.bind f).toOption = o.toOption.elim Option.none fun a => (f a).toOption := by
  by_cases h : o.Dom
  · simp_rw [h.toOption, h.bind]
    rfl
  · rw [Part.toOption_eq_none_iff.2 h]
    

Proof state:
case neg
α : Type u_1
β : Type u_2
γ : Type u_3
f : α → Part β
o : Part α
inst✝² : Decidable o.Dom
inst✝¹ : (a : α) → Decidable (f a).Dom
inst✝ : Decidable (Part.bind o f).Dom
h : ¬o.Dom
⊢ toOption (Part.bind o f) = Option.elim Option.none Option.none fun a => toOption (f a)

Next tactic:
exact Part.toOption_eq_none_iff.2 fun ho => h ho.of_bind
theorem bind_assoc {γ} (f : Part α) (g : α → Part β) (k : β → Part γ) :
    (f.bind g).bind k = f.bind fun x => (g x).bind k :=
  ext fun a => by
    

Proof state:
α : Type u_1
β : Type u_2
γ✝ : Type u_3
γ : Type u_4
f : Part α
g : α → Part β
k : β → Part γ
a : γ
⊢ a ∈ Part.bind (Part.bind f g) k ↔ a ∈ Part.bind f fun x => Part.bind (g x) k

Next tactic:
simp only [mem_bind_iff]
theorem bind_assoc {γ} (f : Part α) (g : α → Part β) (k : β → Part γ) :
    (f.bind g).bind k = f.bind fun x => (g x).bind k :=
  ext fun a => by
    simp only [mem_bind_iff]
    

Proof state:
α : Type u_1
β : Type u_2
γ✝ : Type u_3
γ : Type u_4
f : Part α
g : α → Part β
k : β → Part γ
a : γ
⊢ (∃ a_1, (∃ a ∈ f, a_1 ∈ g a) ∧ a ∈ k a_1) ↔ ∃ a_1 ∈ f, ∃ a_2 ∈ g a_1, a ∈ k a_2

Next tactic:
exact ⟨fun ⟨_, ⟨_, h₁, h₂⟩, h₃⟩ => ⟨_, h₁, _, h₂, h₃⟩,
           fun ⟨_, h₁, _, h₂, h₃⟩ => ⟨_, ⟨_, h₁, h₂⟩, h₃⟩⟩
@[simp]
theorem bind_map {γ} (f : α → β) (x) (g : β → Part γ) :
    (map f x).bind g = x.bind fun y => g (f y) := by 

Proof state:
α : Type u_1
β : Type u_2
γ✝ : Type u_3
γ : Type u_4
f : α → β
x : Part α
g : β → Part γ
⊢ Part.bind (map f x) g = Part.bind x fun y => g (f y)

Next tactic:
rw [← bind_some_eq_map, bind_assoc]
@[simp]
theorem bind_map {γ} (f : α → β) (x) (g : β → Part γ) :
    (map f x).bind g = x.bind fun y => g (f y) := by rw [← bind_some_eq_map, bind_assoc]; 

Proof state:
α : Type u_1
β : Type u_2
γ✝ : Type u_3
γ : Type u_4
f : α → β
x : Part α
g : β → Part γ
⊢ (Part.bind x fun x => Part.bind ((some ∘ f) x) g) = Part.bind x fun y => g (f y)

Next tactic:
simp
@[simp]
theorem map_bind {γ} (f : α → Part β) (x : Part α) (g : β → γ) :
    map g (x.bind f) = x.bind fun y => map g (f y) := by
  

Proof state:
α : Type u_1
β : Type u_2
γ✝ : Type u_3
γ : Type u_4
f : α → Part β
x : Part α
g : β → γ
⊢ map g (Part.bind x f) = Part.bind x fun y => map g (f y)

Next tactic:
rw [← bind_some_eq_map, bind_assoc]
@[simp]
theorem map_bind {γ} (f : α → Part β) (x : Part α) (g : β → γ) :
    map g (x.bind f) = x.bind fun y => map g (f y) := by
  rw [← bind_some_eq_map, bind_assoc]; 

Proof state:
α : Type u_1
β : Type u_2
γ✝ : Type u_3
γ : Type u_4
f : α → Part β
x : Part α
g : β → γ
⊢ (Part.bind x fun x => Part.bind (f x) (some ∘ g)) = Part.bind x fun y => map g (f y)

Next tactic:
simp [bind_some_eq_map]
theorem map_map (g : β → γ) (f : α → β) (o : Part α) : map g (map f o) = map (g ∘ f) o := by
  

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
g : β → γ
f : α → β
o : Part α
⊢ map g (map f o) = map (g ∘ f) o

Next tactic:
erw [← bind_some_eq_map, bind_map, bind_some_eq_map]
instance : LawfulMonad
      Part where
  bind_pure_comp := @bind_some_eq_map
  id_map f := by cases f; rfl
  pure_bind := @bind_some
  bind_assoc := @bind_assoc
  map_const := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
⊢ ∀ {α β : Type ?u.30825}, Functor.mapConst = Functor.map ∘ const β

Next tactic:
simp [Functor.mapConst, Functor.map]
instance : LawfulMonad
      Part where
  bind_pure_comp := @bind_some_eq_map
  id_map f := by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
α✝ : Type ?u.30825
f : Part α✝
⊢ id <$> f = f

Next tactic:
cases f
instance : LawfulMonad
      Part where
  bind_pure_comp := @bind_some_eq_map
  id_map f := by cases f; 

Proof state:
case mk
α : Type u_1
β : Type u_2
γ : Type u_3
α✝ : Type ?u.30825
Dom✝ : Prop
get✝ : Dom✝ → α✝
⊢ id <$> { Dom := Dom✝, get := get✝ } = { Dom := Dom✝, get := get✝ }

Next tactic:
rfl
instance : LawfulMonad
      Part where
  bind_pure_comp := @bind_some_eq_map
  id_map f := by cases f; rfl
  pure_bind := @bind_some
  bind_assoc := @bind_assoc
  map_const := by simp [Functor.mapConst, Functor.map]
  --Porting TODO : In Lean3 these were automatic by a tactic
  seqLeft_eq x y := ext'
    (by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
α✝ β✝ : Type ?u.30825
x : Part α✝
y : Part β✝
⊢ (SeqLeft.seqLeft x fun x => y).Dom ↔ (Seq.seq (const β✝ <$> x) fun x => y).Dom

Next tactic:
simp [SeqLeft.seqLeft, Part.bind, assert, Seq.seq, const, (· <$> ·), and_comm]
instance : LawfulMonad
      Part where
  bind_pure_comp := @bind_some_eq_map
  id_map f := by cases f; rfl
  pure_bind := @bind_some
  bind_assoc := @bind_assoc
  map_const := by simp [Functor.mapConst, Functor.map]
  --Porting TODO : In Lean3 these were automatic by a tactic
  seqLeft_eq x y := ext'
    (by simp [SeqLeft.seqLeft, Part.bind, assert, Seq.seq, const, (· <$> ·), and_comm])
    (fun _ _ => rfl)
  seqRight_eq x y := ext'
    (by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
α✝ β✝ : Type ?u.30825
x : Part α✝
y : Part β✝
⊢ (SeqRight.seqRight x fun x => y).Dom ↔ (Seq.seq (const α✝ id <$> x) fun x => y).Dom

Next tactic:
simp [SeqRight.seqRight, Part.bind, assert, Seq.seq, const, (· <$> ·), and_comm]
instance : LawfulMonad
      Part where
  bind_pure_comp := @bind_some_eq_map
  id_map f := by cases f; rfl
  pure_bind := @bind_some
  bind_assoc := @bind_assoc
  map_const := by simp [Functor.mapConst, Functor.map]
  --Porting TODO : In Lean3 these were automatic by a tactic
  seqLeft_eq x y := ext'
    (by simp [SeqLeft.seqLeft, Part.bind, assert, Seq.seq, const, (· <$> ·), and_comm])
    (fun _ _ => rfl)
  seqRight_eq x y := ext'
    (by simp [SeqRight.seqRight, Part.bind, assert, Seq.seq, const, (· <$> ·), and_comm])
    (fun _ _ => rfl)
  pure_seq x y := ext'
    (by 

Proof state:
α : Type u_1
β : Type u_2
γ : Type u_3
α✝ β✝ : Type ?u.30825
x : α✝ → β✝
y : Part α✝
⊢ (Seq.seq (pure x) fun x => y).Dom ↔ (x <$> y).Dom

Next tactic:
simp [Seq.seq, Part.bind, assert, (· <$> ·), pure]