File: .lake/packages/lean4/src/lean/Init/Core.lean

full_name: inline
code: /--
`inline (f x)` is an indication to the compiler to inline the definition of `f`
at the application site itself (by comparison to the `@[inline]` attribute,
which applies to all applications of the function).
-/
@[simp] def inline {α : Sort u} (a : α) : α 
goal: α

full_name: id_def
code: theorem id_def {α : Sort u} (a : α) : id a = a 
goal: id a = a

full_name: flip
code: /--
`flip f a b` is `f b a`. It is useful for "point-free" programming,
since it can sometimes be used to avoid introducing variables.
For example, `(·<·)` is the less-than relation,
and `flip (·<·)` is the greater-than relation.
-/
@[inline] def flip {α : Sort u} {β : Sort v} {φ : Sort w} (f : α → β → φ) : β → α → φ 
goal: β → α → φ

full_name: Function.const_apply
code: @[simp] theorem Function.const_apply {y : β} {x : α} : const α y x = y 
goal: Function.const α y x = y

full_name: Function.comp_apply
code: @[simp] theorem Function.comp_apply {f : β → δ} {g : α → β} {x : α} : comp f g x = f (g x) 
goal: (f ∘ g) x = f (g x)

full_name: Function.comp_def
code: theorem Function.comp_def {α β δ} (f : β → δ) (g : α → β) : f ∘ g = fun x => f (g x) 
goal: f ∘ g = fun x => f (g x)

full_name: Empty.elim
code: /--
`Empty.elim : Empty → C` says that a value of any type can be constructed from
`Empty`. This can be thought of as a compiler-checked assertion that a code path is unreachable.

This is a non-dependent variant of `Empty.rec`.
-/
@[macro_inline] def Empty.elim {C : Sort u} : Empty → C 
goal: Empty → C

full_name: «instDecidableEqEmpty_.lake»
code: /-- Decidable equality for Empty -/
instance : DecidableEq Empty 
goal: DecidableEq Empty

full_name: PEmpty.elim
code: /--
`PEmpty.elim : Empty → C` says that a value of any type can be constructed from
`PEmpty`. This can be thought of as a compiler-checked assertion that a code path is unreachable.

This is a non-dependent variant of `PEmpty.rec`.
-/
@[macro_inline] def PEmpty.elim {C : Sort _} : PEmpty → C 
goal: PEmpty → C

full_name: «instDecidableEqPEmpty_.lake»
code: /-- Decidable equality for PEmpty -/
instance : DecidableEq PEmpty 
goal: DecidableEq PEmpty

full_name: Thunk.mk
code: /--
  Thunks are "lazy" values that are evaluated when first accessed using `Thunk.get/map/bind`.
  The value is then stored and not recomputed for all further accesses. -/
-- NOTE: the runtime has special support for the `Thunk` type to implement this behavior
structure Thunk (α : Type u) : Type u where
  /-- Constructs a new thunk from a function `Unit → α`
  that will be called when the thunk is forced. -/
  mk ::
  /-- Extract the getter function out of a thunk. Use `Thunk.get` instead. -/
  private fn : Unit → α
goal: Thunk α

full_name: Thunk
code: /--
  Thunks are "lazy" values that are evaluated when first accessed using `Thunk.get/map/bind`.
  The value is then stored and not recomputed for all further accesses. -/
-- NOTE: the runtime has special support for the `Thunk` type to implement this behavior
structure Thunk (α : Type u) : Type u where
  /-- Constructs a new thunk from a function `Unit → α`
  that will be called when the thunk is forced. -/
  mk ::
  /-- Extract the getter function out of a thunk. Use `Thunk.get` instead. -/
  private fn : Unit → α
goal: Type u

full_name: _private.«.lake».packages.lean4.src.lean.Init.Core.0.Thunk.fn
code: /--
  Thunks are "lazy" values that are evaluated when first accessed using `Thunk.get/map/bind`.
  The value is then stored and not recomputed for all further accesses. -/
-- NOTE: the runtime has special support for the `Thunk` type to implement this behavior
structure Thunk (α : Type u) : Type u where
  /-- Constructs a new thunk from a function `Unit → α`
  that will be called when the thunk is forced. -/
  mk ::
  /-- Extract the getter function out of a thunk. Use `Thunk.get` instead. -/
  private fn : Unit → α
goal: Unit → α

full_name: Thunk.pure
code: /-- Store a value in a thunk. Note that the value has already been computed, so there is no laziness. -/
@[extern "lean_thunk_pure"] protected def Thunk.pure (a : α) : Thunk α 
goal: Thunk α

full_name: Thunk.get
code: /--
Forces a thunk to extract the value. This will cache the result,
so a second call to the same function will return the value in O(1)
instead of calling the stored getter function.
-/
-- NOTE: we use `Thunk.get` instead of `Thunk.fn` as the accessor primitive as the latter has an additional `Unit` argument
@[extern "lean_thunk_get_own"] protected def Thunk.get (x : @& Thunk α) : α 
goal: α

full_name: Thunk.map
code: /-- Map a function over a thunk. -/
@[inline] protected def Thunk.map (f : α → β) (x : Thunk α) : Thunk β 
goal: Thunk β

full_name: Thunk.bind
code: /-- Constructs a thunk that applies `f` to the result of `x` when forced. -/
@[inline] protected def Thunk.bind (x : Thunk α) (f : α → Thunk β) : Thunk β 
goal: Thunk β

full_name: Thunk.sizeOf_eq
code: @[simp] theorem Thunk.sizeOf_eq [SizeOf α] (a : Thunk α) : sizeOf a = 1 + sizeOf a.get 
goal: sizeOf a = 1 + sizeOf a.get

full_name: thunkCoe
code: instance thunkCoe : CoeTail α (Thunk α) 
goal: CoeTail α (Thunk α)

full_name: Iff.mp
code: /--
If and only if, or logical bi-implication. `a ↔ b` means that `a` implies `b` and vice versa.
By `propext`, this implies that `a` and `b` are equal and hence any expression involving `a`
is equivalent to the corresponding expression with `b` instead.
-/
structure Iff (a b : Prop) : Prop where
  /-- If `a → b` and `b → a` then `a` and `b` are equivalent. -/
  intro ::
  /-- Modus ponens for if and only if. If `a ↔ b` and `a`, then `b`. -/
  mp : a → b
  /-- Modus ponens for if and only if, reversed. If `a ↔ b` and `b`, then `a`. -/
  mpr : b → a
goal: a → b

full_name: Iff
code: /--
If and only if, or logical bi-implication. `a ↔ b` means that `a` implies `b` and vice versa.
By `propext`, this implies that `a` and `b` are equal and hence any expression involving `a`
is equivalent to the corresponding expression with `b` instead.
-/
structure Iff (a b : Prop) : Prop where
  /-- If `a → b` and `b → a` then `a` and `b` are equivalent. -/
  intro ::
  /-- Modus ponens for if and only if. If `a ↔ b` and `a`, then `b`. -/
  mp : a → b
  /-- Modus ponens for if and only if, reversed. If `a ↔ b` and `b`, then `a`. -/
  mpr : b → a
goal: Prop

full_name: Iff.mpr
code: /--
If and only if, or logical bi-implication. `a ↔ b` means that `a` implies `b` and vice versa.
By `propext`, this implies that `a` and `b` are equal and hence any expression involving `a`
is equivalent to the corresponding expression with `b` instead.
-/
structure Iff (a b : Prop) : Prop where
  /-- If `a → b` and `b → a` then `a` and `b` are equivalent. -/
  intro ::
  /-- Modus ponens for if and only if. If `a ↔ b` and `a`, then `b`. -/
  mp : a → b
  /-- Modus ponens for if and only if, reversed. If `a ↔ b` and `b`, then `a`. -/
  mpr : b → a
goal: b → a

full_name: Iff.intro
code: /--
If and only if, or logical bi-implication. `a ↔ b` means that `a` implies `b` and vice versa.
By `propext`, this implies that `a` and `b` are equal and hence any expression involving `a`
is equivalent to the corresponding expression with `b` instead.
-/
structure Iff (a b : Prop) : Prop where
  /-- If `a → b` and `b → a` then `a` and `b` are equivalent. -/
  intro ::
  /-- Modus ponens for if and only if. If `a ↔ b` and `a`, then `b`. -/
  mp : a → b
  /-- Modus ponens for if and only if, reversed. If `a ↔ b` and `b`, then `a`. -/
  mpr : b → a
goal: a ↔ b

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_Iff_1»
code: @[inherit_doc] infix:20 " <-> " => Iff
goal: Lean.PrettyPrinter.Unexpander

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term_<->__1»
code: @[inherit_doc] infix:20 " <-> " => Iff
goal: Lean.Macro

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_Iff_2»
code: @[inherit_doc] infix:20 " ↔ "   => Iff
goal: Lean.PrettyPrinter.Unexpander

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term_↔__1»
code: @[inherit_doc] infix:20 " ↔ "   => Iff
goal: Lean.Macro

full_name: Sum.inl
code: /--
`Sum α β`, or `α ⊕ β`, is the disjoint union of types `α` and `β`.
An element of `α ⊕ β` is either of the form `.inl a` where `a : α`,
or `.inr b` where `b : β`.
-/
inductive Sum (α : Type u) (β : Type v) where
  /-- Left injection into the sum type `α ⊕ β`. If `a : α` then `.inl a : α ⊕ β`. -/
  | inl (val : α) : Sum α β
  /-- Right injection into the sum type `α ⊕ β`. If `b : β` then `.inr b : α ⊕ β`. -/
  | inr (val : β) : Sum α β
goal: α ⊕ β

full_name: Sum.inr
code: /--
`Sum α β`, or `α ⊕ β`, is the disjoint union of types `α` and `β`.
An element of `α ⊕ β` is either of the form `.inl a` where `a : α`,
or `.inr b` where `b : β`.
-/
inductive Sum (α : Type u) (β : Type v) where
  /-- Left injection into the sum type `α ⊕ β`. If `a : α` then `.inl a : α ⊕ β`. -/
  | inl (val : α) : Sum α β
  /-- Right injection into the sum type `α ⊕ β`. If `b : β` then `.inr b : α ⊕ β`. -/
  | inr (val : β) : Sum α β
goal: α ⊕ β

full_name: Sum
code: /--
`Sum α β`, or `α ⊕ β`, is the disjoint union of types `α` and `β`.
An element of `α ⊕ β` is either of the form `.inl a` where `a : α`,
or `.inr b` where `b : β`.
-/
inductive Sum (α : Type u) (β : Type v) where
  /-- Left injection into the sum type `α ⊕ β`. If `a : α` then `.inl a : α ⊕ β`. -/
  | inl (val : α) : Sum α β
  /-- Right injection into the sum type `α ⊕ β`. If `b : β` then `.inr b : α ⊕ β`. -/
  | inr (val : β) : Sum α β
goal: Type (max u v)

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_Sum_1»
code: @[inherit_doc] infixr:30 " ⊕ " => Sum
goal: Lean.PrettyPrinter.Unexpander

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term_⊕__1»
code: @[inherit_doc] infixr:30 " ⊕ " => Sum
goal: Lean.Macro

full_name: PSum.inl
code: /--
`PSum α β`, or `α ⊕' β`, is the disjoint union of types `α` and `β`.
It differs from `α ⊕ β` in that it allows `α` and `β` to have arbitrary sorts
`Sort u` and `Sort v`, instead of restricting to `Type u` and `Type v`. This means
that it can be used in situations where one side is a proposition, like `True ⊕' Nat`.

The reason this is not the default is that this type lives in the universe `Sort (max 1 u v)`,
which can cause problems for universe level unification,
because the equation `max 1 u v = ?u + 1` has no solution in level arithmetic.
`PSum` is usually only used in automation that constructs sums of arbitrary types.
-/
inductive PSum (α : Sort u) (β : Sort v) where
  /-- Left injection into the sum type `α ⊕' β`. If `a : α` then `.inl a : α ⊕' β`. -/
  | inl (val : α) : PSum α β
  /-- Right injection into the sum type `α ⊕' β`. If `b : β` then `.inr b : α ⊕' β`. -/
  | inr (val : β) : PSum α β
goal: α ⊕' β

full_name: PSum.inr
code: /--
`PSum α β`, or `α ⊕' β`, is the disjoint union of types `α` and `β`.
It differs from `α ⊕ β` in that it allows `α` and `β` to have arbitrary sorts
`Sort u` and `Sort v`, instead of restricting to `Type u` and `Type v`. This means
that it can be used in situations where one side is a proposition, like `True ⊕' Nat`.

The reason this is not the default is that this type lives in the universe `Sort (max 1 u v)`,
which can cause problems for universe level unification,
because the equation `max 1 u v = ?u + 1` has no solution in level arithmetic.
`PSum` is usually only used in automation that constructs sums of arbitrary types.
-/
inductive PSum (α : Sort u) (β : Sort v) where
  /-- Left injection into the sum type `α ⊕' β`. If `a : α` then `.inl a : α ⊕' β`. -/
  | inl (val : α) : PSum α β
  /-- Right injection into the sum type `α ⊕' β`. If `b : β` then `.inr b : α ⊕' β`. -/
  | inr (val : β) : PSum α β
goal: α ⊕' β

full_name: PSum
code: /--
`PSum α β`, or `α ⊕' β`, is the disjoint union of types `α` and `β`.
It differs from `α ⊕ β` in that it allows `α` and `β` to have arbitrary sorts
`Sort u` and `Sort v`, instead of restricting to `Type u` and `Type v`. This means
that it can be used in situations where one side is a proposition, like `True ⊕' Nat`.

The reason this is not the default is that this type lives in the universe `Sort (max 1 u v)`,
which can cause problems for universe level unification,
because the equation `max 1 u v = ?u + 1` has no solution in level arithmetic.
`PSum` is usually only used in automation that constructs sums of arbitrary types.
-/
inductive PSum (α : Sort u) (β : Sort v) where
  /-- Left injection into the sum type `α ⊕' β`. If `a : α` then `.inl a : α ⊕' β`. -/
  | inl (val : α) : PSum α β
  /-- Right injection into the sum type `α ⊕' β`. If `b : β` then `.inr b : α ⊕' β`. -/
  | inr (val : β) : PSum α β
goal: Sort (max (max 1 u) v)

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_PSum_1»
code: @[inherit_doc] infixr:30 " ⊕' " => PSum
goal: Lean.PrettyPrinter.Unexpander

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term_⊕'__1»
code: @[inherit_doc] infixr:30 " ⊕' " => PSum
goal: Lean.Macro

full_name: instInhabitedPSum
code: instance {α β} [Inhabited α] : Inhabited (PSum α β) 
goal: Inhabited (α ⊕' β)

full_name: instInhabitedPSum_1
code: instance {α β} [Inhabited β] : Inhabited (PSum α β) 
goal: Inhabited (α ⊕' β)

full_name: Sigma.mk
code: /--
`Sigma β`, also denoted `Σ a : α, β a` or `(a : α) × β a`, is the type of dependent pairs
whose first component is `a : α` and whose second component is `b : β a`
(so the type of the second component can depend on the value of the first component).
It is sometimes known as the dependent sum type, since it is the type level version
of an indexed summation.
-/
@[pp_using_anonymous_constructor]
structure Sigma {α : Type u} (β : α → Type v) where
  /-- Constructor for a dependent pair. If `a : α` and `b : β a` then `⟨a, b⟩ : Sigma β`.
  (This will usually require a type ascription to determine `β`
  since it is not determined from `a` and `b` alone.) -/
  mk ::
  /-- The first component of a dependent pair. If `p : @Sigma α β` then `p.1 : α`. -/
  fst : α
  /-- The second component of a dependent pair. If `p : Sigma β` then `p.2 : β p.1`. -/
  snd : β fst
goal: Sigma β

full_name: Sigma.snd
code: /--
`Sigma β`, also denoted `Σ a : α, β a` or `(a : α) × β a`, is the type of dependent pairs
whose first component is `a : α` and whose second component is `b : β a`
(so the type of the second component can depend on the value of the first component).
It is sometimes known as the dependent sum type, since it is the type level version
of an indexed summation.
-/
@[pp_using_anonymous_constructor]
structure Sigma {α : Type u} (β : α → Type v) where
  /-- Constructor for a dependent pair. If `a : α` and `b : β a` then `⟨a, b⟩ : Sigma β`.
  (This will usually require a type ascription to determine `β`
  since it is not determined from `a` and `b` alone.) -/
  mk ::
  /-- The first component of a dependent pair. If `p : @Sigma α β` then `p.1 : α`. -/
  fst : α
  /-- The second component of a dependent pair. If `p : Sigma β` then `p.2 : β p.1`. -/
  snd : β fst
goal: β self.fst

full_name: Sigma.fst
code: /--
`Sigma β`, also denoted `Σ a : α, β a` or `(a : α) × β a`, is the type of dependent pairs
whose first component is `a : α` and whose second component is `b : β a`
(so the type of the second component can depend on the value of the first component).
It is sometimes known as the dependent sum type, since it is the type level version
of an indexed summation.
-/
@[pp_using_anonymous_constructor]
structure Sigma {α : Type u} (β : α → Type v) where
  /-- Constructor for a dependent pair. If `a : α` and `b : β a` then `⟨a, b⟩ : Sigma β`.
  (This will usually require a type ascription to determine `β`
  since it is not determined from `a` and `b` alone.) -/
  mk ::
  /-- The first component of a dependent pair. If `p : @Sigma α β` then `p.1 : α`. -/
  fst : α
  /-- The second component of a dependent pair. If `p : Sigma β` then `p.2 : β p.1`. -/
  snd : β fst
goal: α

full_name: Sigma
code: /--
`Sigma β`, also denoted `Σ a : α, β a` or `(a : α) × β a`, is the type of dependent pairs
whose first component is `a : α` and whose second component is `b : β a`
(so the type of the second component can depend on the value of the first component).
It is sometimes known as the dependent sum type, since it is the type level version
of an indexed summation.
-/
@[pp_using_anonymous_constructor]
structure Sigma {α : Type u} (β : α → Type v) where
  /-- Constructor for a dependent pair. If `a : α` and `b : β a` then `⟨a, b⟩ : Sigma β`.
  (This will usually require a type ascription to determine `β`
  since it is not determined from `a` and `b` alone.) -/
  mk ::
  /-- The first component of a dependent pair. If `p : @Sigma α β` then `p.1 : α`. -/
  fst : α
  /-- The second component of a dependent pair. If `p : Sigma β` then `p.2 : β p.1`. -/
  snd : β fst
goal: Type (max u v)

full_name: PSigma.snd
code: /--
`PSigma β`, also denoted `Σ' a : α, β a` or `(a : α) ×' β a`, is the type of dependent pairs
whose first component is `a : α` and whose second component is `b : β a`
(so the type of the second component can depend on the value of the first component).
It differs from `Σ a : α, β a` in that it allows `α` and `β` to have arbitrary sorts
`Sort u` and `Sort v`, instead of restricting to `Type u` and `Type v`. This means
that it can be used in situations where one side is a proposition, like `(p : Nat) ×' p = p`.

The reason this is not the default is that this type lives in the universe `Sort (max 1 u v)`,
which can cause problems for universe level unification,
because the equation `max 1 u v = ?u + 1` has no solution in level arithmetic.
`PSigma` is usually only used in automation that constructs pairs of arbitrary types.
-/
@[pp_using_anonymous_constructor]
structure PSigma {α : Sort u} (β : α → Sort v) where
  /-- Constructor for a dependent pair. If `a : α` and `b : β a` then `⟨a, b⟩ : PSigma β`.
  (This will usually require a type ascription to determine `β`
  since it is not determined from `a` and `b` alone.) -/
  mk ::
  /-- The first component of a dependent pair. If `p : @Sigma α β` then `p.1 : α`. -/
  fst : α
  /-- The second component of a dependent pair. If `p : Sigma β` then `p.2 : β p.1`. -/
  snd : β fst
goal: β self.fst

full_name: PSigma
code: /--
`PSigma β`, also denoted `Σ' a : α, β a` or `(a : α) ×' β a`, is the type of dependent pairs
whose first component is `a : α` and whose second component is `b : β a`
(so the type of the second component can depend on the value of the first component).
It differs from `Σ a : α, β a` in that it allows `α` and `β` to have arbitrary sorts
`Sort u` and `Sort v`, instead of restricting to `Type u` and `Type v`. This means
that it can be used in situations where one side is a proposition, like `(p : Nat) ×' p = p`.

The reason this is not the default is that this type lives in the universe `Sort (max 1 u v)`,
which can cause problems for universe level unification,
because the equation `max 1 u v = ?u + 1` has no solution in level arithmetic.
`PSigma` is usually only used in automation that constructs pairs of arbitrary types.
-/
@[pp_using_anonymous_constructor]
structure PSigma {α : Sort u} (β : α → Sort v) where
  /-- Constructor for a dependent pair. If `a : α` and `b : β a` then `⟨a, b⟩ : PSigma β`.
  (This will usually require a type ascription to determine `β`
  since it is not determined from `a` and `b` alone.) -/
  mk ::
  /-- The first component of a dependent pair. If `p : @Sigma α β` then `p.1 : α`. -/
  fst : α
  /-- The second component of a dependent pair. If `p : Sigma β` then `p.2 : β p.1`. -/
  snd : β fst
goal: Sort (max (max 1 u) v)

full_name: PSigma.mk
code: /--
`PSigma β`, also denoted `Σ' a : α, β a` or `(a : α) ×' β a`, is the type of dependent pairs
whose first component is `a : α` and whose second component is `b : β a`
(so the type of the second component can depend on the value of the first component).
It differs from `Σ a : α, β a` in that it allows `α` and `β` to have arbitrary sorts
`Sort u` and `Sort v`, instead of restricting to `Type u` and `Type v`. This means
that it can be used in situations where one side is a proposition, like `(p : Nat) ×' p = p`.

The reason this is not the default is that this type lives in the universe `Sort (max 1 u v)`,
which can cause problems for universe level unification,
because the equation `max 1 u v = ?u + 1` has no solution in level arithmetic.
`PSigma` is usually only used in automation that constructs pairs of arbitrary types.
-/
@[pp_using_anonymous_constructor]
structure PSigma {α : Sort u} (β : α → Sort v) where
  /-- Constructor for a dependent pair. If `a : α` and `b : β a` then `⟨a, b⟩ : PSigma β`.
  (This will usually require a type ascription to determine `β`
  since it is not determined from `a` and `b` alone.) -/
  mk ::
  /-- The first component of a dependent pair. If `p : @Sigma α β` then `p.1 : α`. -/
  fst : α
  /-- The second component of a dependent pair. If `p : Sigma β` then `p.2 : β p.1`. -/
  snd : β fst
goal: PSigma β

full_name: PSigma.fst
code: /--
`PSigma β`, also denoted `Σ' a : α, β a` or `(a : α) ×' β a`, is the type of dependent pairs
whose first component is `a : α` and whose second component is `b : β a`
(so the type of the second component can depend on the value of the first component).
It differs from `Σ a : α, β a` in that it allows `α` and `β` to have arbitrary sorts
`Sort u` and `Sort v`, instead of restricting to `Type u` and `Type v`. This means
that it can be used in situations where one side is a proposition, like `(p : Nat) ×' p = p`.

The reason this is not the default is that this type lives in the universe `Sort (max 1 u v)`,
which can cause problems for universe level unification,
because the equation `max 1 u v = ?u + 1` has no solution in level arithmetic.
`PSigma` is usually only used in automation that constructs pairs of arbitrary types.
-/
@[pp_using_anonymous_constructor]
structure PSigma {α : Sort u} (β : α → Sort v) where
  /-- Constructor for a dependent pair. If `a : α` and `b : β a` then `⟨a, b⟩ : PSigma β`.
  (This will usually require a type ascription to determine `β`
  since it is not determined from `a` and `b` alone.) -/
  mk ::
  /-- The first component of a dependent pair. If `p : @Sigma α β` then `p.1 : α`. -/
  fst : α
  /-- The second component of a dependent pair. If `p : Sigma β` then `p.2 : β p.1`. -/
  snd : β fst
goal: α

full_name: Exists.intro
code: /--
Existential quantification. If `p : α → Prop` is a predicate, then `∃ x : α, p x`
asserts that there is some `x` of type `α` such that `p x` holds.
To create an existential proof, use the `exists` tactic,
or the anonymous constructor notation `⟨x, h⟩`.
To unpack an existential, use `cases h` where `h` is a proof of `∃ x : α, p x`,
or `let ⟨x, hx⟩ := h` where `.

Because Lean has proof irrelevance, any two proofs of an existential are
definitionally equal. One consequence of this is that it is impossible to recover the
witness of an existential from the mere fact of its existence.
For example, the following does not compile:
```
example (h : ∃ x : Nat, x = x) : Nat :=
  let ⟨x, _⟩ := h  -- fail, because the goal is `Nat : Type`
  x
```
The error message `recursor 'Exists.casesOn' can only eliminate into Prop` means
that this only works when the current goal is another proposition:
```
example (h : ∃ x : Nat, x = x) : True :=
  let ⟨x, _⟩ := h  -- ok, because the goal is `True : Prop`
  trivial
```
-/
inductive Exists {α : Sort u} (p : α → Prop) : Prop where
  /-- Existential introduction. If `a : α` and `h : p a`,
  then `⟨a, h⟩` is a proof that `∃ x : α, p x`. -/
  | intro (w : α) (h : p w) : Exists p
goal: Exists p

full_name: Exists
code: /--
Existential quantification. If `p : α → Prop` is a predicate, then `∃ x : α, p x`
asserts that there is some `x` of type `α` such that `p x` holds.
To create an existential proof, use the `exists` tactic,
or the anonymous constructor notation `⟨x, h⟩`.
To unpack an existential, use `cases h` where `h` is a proof of `∃ x : α, p x`,
or `let ⟨x, hx⟩ := h` where `.

Because Lean has proof irrelevance, any two proofs of an existential are
definitionally equal. One consequence of this is that it is impossible to recover the
witness of an existential from the mere fact of its existence.
For example, the following does not compile:
```
example (h : ∃ x : Nat, x = x) : Nat :=
  let ⟨x, _⟩ := h  -- fail, because the goal is `Nat : Type`
  x
```
The error message `recursor 'Exists.casesOn' can only eliminate into Prop` means
that this only works when the current goal is another proposition:
```
example (h : ∃ x : Nat, x = x) : True :=
  let ⟨x, _⟩ := h  -- ok, because the goal is `True : Prop`
  trivial
```
-/
inductive Exists {α : Sort u} (p : α → Prop) : Prop where
  /-- Existential introduction. If `a : α` and `h : p a`,
  then `⟨a, h⟩` is a proof that `∃ x : α, p x`. -/
  | intro (w : α) (h : p w) : Exists p
goal: Prop

full_name: ForInStep.done
code: /--
Auxiliary type used to compile `for x in xs` notation.

This is the return value of the body of a `ForIn` call,
representing the body of a for loop. It can be:

* `.yield (a : α)`, meaning that we should continue the loop and `a` is the new state.
  `.yield` is produced by `continue` and reaching the bottom of the loop body.
* `.done (a : α)`, meaning that we should early-exit the loop with state `a`.
  `.done` is produced by calls to `break` or `return` in the loop,
-/
inductive ForInStep (α : Type u) where
  /-- `.done a` means that we should early-exit the loop.
  `.done` is produced by calls to `break` or `return` in the loop. -/
  | done  : α → ForInStep α
  /-- `.yield a` means that we should continue the loop.
  `.yield` is produced by `continue` and reaching the bottom of the loop body. -/
  | yield : α → ForInStep α
  deriving Inhabited
goal: α → ForInStep α

full_name: ForInStep
code: /--
Auxiliary type used to compile `for x in xs` notation.

This is the return value of the body of a `ForIn` call,
representing the body of a for loop. It can be:

* `.yield (a : α)`, meaning that we should continue the loop and `a` is the new state.
  `.yield` is produced by `continue` and reaching the bottom of the loop body.
* `.done (a : α)`, meaning that we should early-exit the loop with state `a`.
  `.done` is produced by calls to `break` or `return` in the loop,
-/
inductive ForInStep (α : Type u) where
  /-- `.done a` means that we should early-exit the loop.
  `.done` is produced by calls to `break` or `return` in the loop. -/
  | done  : α → ForInStep α
  /-- `.yield a` means that we should continue the loop.
  `.yield` is produced by `continue` and reaching the bottom of the loop body. -/
  | yield : α → ForInStep α
  deriving Inhabited
goal: Type u

full_name: instInhabitedForInStep
code: /--
Auxiliary type used to compile `for x in xs` notation.

This is the return value of the body of a `ForIn` call,
representing the body of a for loop. It can be:

* `.yield (a : α)`, meaning that we should continue the loop and `a` is the new state.
  `.yield` is produced by `continue` and reaching the bottom of the loop body.
* `.done (a : α)`, meaning that we should early-exit the loop with state `a`.
  `.done` is produced by calls to `break` or `return` in the loop,
-/
inductive ForInStep (α : Type u) where
  /-- `.done a` means that we should early-exit the loop.
  `.done` is produced by calls to `break` or `return` in the loop. -/
  | done  : α → ForInStep α
  /-- `.yield a` means that we should continue the loop.
  `.yield` is produced by `continue` and reaching the bottom of the loop body. -/
  | yield : α → ForInStep α
  deriving Inhabited
goal: {a : Type u_1} → [inst : Inhabited a] → Inhabited (ForInStep a)

full_name: ForInStep.yield
code: /--
Auxiliary type used to compile `for x in xs` notation.

This is the return value of the body of a `ForIn` call,
representing the body of a for loop. It can be:

* `.yield (a : α)`, meaning that we should continue the loop and `a` is the new state.
  `.yield` is produced by `continue` and reaching the bottom of the loop body.
* `.done (a : α)`, meaning that we should early-exit the loop with state `a`.
  `.done` is produced by calls to `break` or `return` in the loop,
-/
inductive ForInStep (α : Type u) where
  /-- `.done a` means that we should early-exit the loop.
  `.done` is produced by calls to `break` or `return` in the loop. -/
  | done  : α → ForInStep α
  /-- `.yield a` means that we should continue the loop.
  `.yield` is produced by `continue` and reaching the bottom of the loop body. -/
  | yield : α → ForInStep α
  deriving Inhabited
goal: α → ForInStep α

full_name: ForIn
code: /--
`ForIn m ρ α` is the typeclass which supports `for x in xs` notation.
Here `xs : ρ` is the type of the collection to iterate over, `x : α`
is the element type which is made available inside the loop, and `m` is the monad
for the encompassing `do` block.
-/
class ForIn (m : Type u₁ → Type u₂) (ρ : Type u) (α : outParam (Type v)) where
  /-- `forIn x b f : m β` runs a for-loop in the monad `m` with additional state `β`.
  This traverses over the "contents" of `x`, and passes the elements `a : α` to
  `f : α → β → m (ForInStep β)`. `b : β` is the initial state, and the return value
  of `f` is the new state as well as a directive `.done` or `.yield`
  which indicates whether to abort early or continue iteration.

  The expression
  ```
  let mut b := ...
  for x in xs do
    b ← foo x b
  ```
  in a `do` block is syntactic sugar for:
  ```
  let b := ...
  let b ← forIn xs b (fun x b => do
    let b ← foo x b
    return .yield b)
  ```
  (Here `b` corresponds to the variables mutated in the loop.) -/
  forIn {β} [Monad m] (x : ρ) (b : β) (f : α → β → m (ForInStep β)) : m β
goal: Type (max (max (max u (u₁ + 1)) u₂) v)

full_name: ForIn.forIn
code: /--
`ForIn m ρ α` is the typeclass which supports `for x in xs` notation.
Here `xs : ρ` is the type of the collection to iterate over, `x : α`
is the element type which is made available inside the loop, and `m` is the monad
for the encompassing `do` block.
-/
class ForIn (m : Type u₁ → Type u₂) (ρ : Type u) (α : outParam (Type v)) where
  /-- `forIn x b f : m β` runs a for-loop in the monad `m` with additional state `β`.
  This traverses over the "contents" of `x`, and passes the elements `a : α` to
  `f : α → β → m (ForInStep β)`. `b : β` is the initial state, and the return value
  of `f` is the new state as well as a directive `.done` or `.yield`
  which indicates whether to abort early or continue iteration.

  The expression
  ```
  let mut b := ...
  for x in xs do
    b ← foo x b
  ```
  in a `do` block is syntactic sugar for:
  ```
  let b := ...
  let b ← forIn xs b (fun x b => do
    let b ← foo x b
    return .yield b)
  ```
  (Here `b` corresponds to the variables mutated in the loop.) -/
  forIn {β} [Monad m] (x : ρ) (b : β) (f : α → β → m (ForInStep β)) : m β
goal: m β

full_name: ForIn'.forIn'
code: /--
`ForIn' m ρ α d` is a variation on the `ForIn m ρ α` typeclass which supports the
`for h : x in xs` notation. It is the same as `for x in xs` except that `h : x ∈ xs`
is provided as an additional argument to the body of the for-loop.
-/
class ForIn' (m : Type u₁ → Type u₂) (ρ : Type u) (α : outParam (Type v)) (d : outParam $ Membership α ρ) where
  /-- `forIn' x b f : m β` runs a for-loop in the monad `m` with additional state `β`.
  This traverses over the "contents" of `x`, and passes the elements `a : α` along
  with a proof that `a ∈ x` to `f : (a : α) → a ∈ x → β → m (ForInStep β)`.
  `b : β` is the initial state, and the return value
  of `f` is the new state as well as a directive `.done` or `.yield`
  which indicates whether to abort early or continue iteration. -/
  forIn' {β} [Monad m] (x : ρ) (b : β) (f : (a : α) → a ∈ x → β → m (ForInStep β)) : m β
goal: m β

full_name: ForIn'
code: /--
`ForIn' m ρ α d` is a variation on the `ForIn m ρ α` typeclass which supports the
`for h : x in xs` notation. It is the same as `for x in xs` except that `h : x ∈ xs`
is provided as an additional argument to the body of the for-loop.
-/
class ForIn' (m : Type u₁ → Type u₂) (ρ : Type u) (α : outParam (Type v)) (d : outParam $ Membership α ρ) where
  /-- `forIn' x b f : m β` runs a for-loop in the monad `m` with additional state `β`.
  This traverses over the "contents" of `x`, and passes the elements `a : α` along
  with a proof that `a ∈ x` to `f : (a : α) → a ∈ x → β → m (ForInStep β)`.
  `b : β` is the initial state, and the return value
  of `f` is the new state as well as a directive `.done` or `.yield`
  which indicates whether to abort early or continue iteration. -/
  forIn' {β} [Monad m] (x : ρ) (b : β) (f : (a : α) → a ∈ x → β → m (ForInStep β)) : m β
goal: Type (max (max (max u (u₁ + 1)) u₂) v)

full_name: DoResultPRBC.break
code: /--
Auxiliary type used to compile `do` notation. It is used when compiling a do block
nested inside a combinator like `tryCatch`. It encodes the possible ways the
block can exit:
* `pure (a : α) s` means that the block exited normally with return value `a`.
* `return (b : β) s` means that the block exited via a `return b` early-exit command.
* `break s` means that `break` was called, meaning that we should exit
  from the containing loop.
* `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop.

All cases return a value `s : σ` which bundles all the mutable variables of the do-block.
-/
inductive DoResultPRBC (α β σ : Type u) where
  /-- `pure (a : α) s` means that the block exited normally with return value `a` -/
  | pure : α → σ → DoResultPRBC α β σ
  /-- `return (b : β) s` means that the block exited via a `return b` early-exit command -/
  | return : β → σ → DoResultPRBC α β σ
  /-- `break s` means that `break` was called, meaning that we should exit
  from the containing loop -/
  | break : σ → DoResultPRBC α β σ
  /-- `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop -/
  | continue : σ → DoResultPRBC α β σ
goal: σ → DoResultPRBC α β σ

full_name: DoResultPRBC.continue
code: /--
Auxiliary type used to compile `do` notation. It is used when compiling a do block
nested inside a combinator like `tryCatch`. It encodes the possible ways the
block can exit:
* `pure (a : α) s` means that the block exited normally with return value `a`.
* `return (b : β) s` means that the block exited via a `return b` early-exit command.
* `break s` means that `break` was called, meaning that we should exit
  from the containing loop.
* `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop.

All cases return a value `s : σ` which bundles all the mutable variables of the do-block.
-/
inductive DoResultPRBC (α β σ : Type u) where
  /-- `pure (a : α) s` means that the block exited normally with return value `a` -/
  | pure : α → σ → DoResultPRBC α β σ
  /-- `return (b : β) s` means that the block exited via a `return b` early-exit command -/
  | return : β → σ → DoResultPRBC α β σ
  /-- `break s` means that `break` was called, meaning that we should exit
  from the containing loop -/
  | break : σ → DoResultPRBC α β σ
  /-- `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop -/
  | continue : σ → DoResultPRBC α β σ
goal: σ → DoResultPRBC α β σ

full_name: DoResultPRBC.pure
code: /--
Auxiliary type used to compile `do` notation. It is used when compiling a do block
nested inside a combinator like `tryCatch`. It encodes the possible ways the
block can exit:
* `pure (a : α) s` means that the block exited normally with return value `a`.
* `return (b : β) s` means that the block exited via a `return b` early-exit command.
* `break s` means that `break` was called, meaning that we should exit
  from the containing loop.
* `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop.

All cases return a value `s : σ` which bundles all the mutable variables of the do-block.
-/
inductive DoResultPRBC (α β σ : Type u) where
  /-- `pure (a : α) s` means that the block exited normally with return value `a` -/
  | pure : α → σ → DoResultPRBC α β σ
  /-- `return (b : β) s` means that the block exited via a `return b` early-exit command -/
  | return : β → σ → DoResultPRBC α β σ
  /-- `break s` means that `break` was called, meaning that we should exit
  from the containing loop -/
  | break : σ → DoResultPRBC α β σ
  /-- `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop -/
  | continue : σ → DoResultPRBC α β σ
goal: α → σ → DoResultPRBC α β σ

full_name: DoResultPRBC.return
code: /--
Auxiliary type used to compile `do` notation. It is used when compiling a do block
nested inside a combinator like `tryCatch`. It encodes the possible ways the
block can exit:
* `pure (a : α) s` means that the block exited normally with return value `a`.
* `return (b : β) s` means that the block exited via a `return b` early-exit command.
* `break s` means that `break` was called, meaning that we should exit
  from the containing loop.
* `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop.

All cases return a value `s : σ` which bundles all the mutable variables of the do-block.
-/
inductive DoResultPRBC (α β σ : Type u) where
  /-- `pure (a : α) s` means that the block exited normally with return value `a` -/
  | pure : α → σ → DoResultPRBC α β σ
  /-- `return (b : β) s` means that the block exited via a `return b` early-exit command -/
  | return : β → σ → DoResultPRBC α β σ
  /-- `break s` means that `break` was called, meaning that we should exit
  from the containing loop -/
  | break : σ → DoResultPRBC α β σ
  /-- `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop -/
  | continue : σ → DoResultPRBC α β σ
goal: β → σ → DoResultPRBC α β σ

full_name: DoResultPRBC
code: /--
Auxiliary type used to compile `do` notation. It is used when compiling a do block
nested inside a combinator like `tryCatch`. It encodes the possible ways the
block can exit:
* `pure (a : α) s` means that the block exited normally with return value `a`.
* `return (b : β) s` means that the block exited via a `return b` early-exit command.
* `break s` means that `break` was called, meaning that we should exit
  from the containing loop.
* `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop.

All cases return a value `s : σ` which bundles all the mutable variables of the do-block.
-/
inductive DoResultPRBC (α β σ : Type u) where
  /-- `pure (a : α) s` means that the block exited normally with return value `a` -/
  | pure : α → σ → DoResultPRBC α β σ
  /-- `return (b : β) s` means that the block exited via a `return b` early-exit command -/
  | return : β → σ → DoResultPRBC α β σ
  /-- `break s` means that `break` was called, meaning that we should exit
  from the containing loop -/
  | break : σ → DoResultPRBC α β σ
  /-- `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop -/
  | continue : σ → DoResultPRBC α β σ
goal: Type u

full_name: DoResultPR
code: /--
Auxiliary type used to compile `do` notation. It is the same as
`DoResultPRBC α β σ` except that `break` and `continue` are not available
because we are not in a loop context.
-/
inductive DoResultPR (α β σ : Type u) where
  /-- `pure (a : α) s` means that the block exited normally with return value `a` -/
  | pure   : α → σ → DoResultPR α β σ
  /-- `return (b : β) s` means that the block exited via a `return b` early-exit command -/
  | return : β → σ → DoResultPR α β σ
goal: Type u

full_name: DoResultPR.pure
code: /--
Auxiliary type used to compile `do` notation. It is the same as
`DoResultPRBC α β σ` except that `break` and `continue` are not available
because we are not in a loop context.
-/
inductive DoResultPR (α β σ : Type u) where
  /-- `pure (a : α) s` means that the block exited normally with return value `a` -/
  | pure   : α → σ → DoResultPR α β σ
  /-- `return (b : β) s` means that the block exited via a `return b` early-exit command -/
  | return : β → σ → DoResultPR α β σ
goal: α → σ → DoResultPR α β σ

full_name: DoResultPR.return
code: /--
Auxiliary type used to compile `do` notation. It is the same as
`DoResultPRBC α β σ` except that `break` and `continue` are not available
because we are not in a loop context.
-/
inductive DoResultPR (α β σ : Type u) where
  /-- `pure (a : α) s` means that the block exited normally with return value `a` -/
  | pure   : α → σ → DoResultPR α β σ
  /-- `return (b : β) s` means that the block exited via a `return b` early-exit command -/
  | return : β → σ → DoResultPR α β σ
goal: β → σ → DoResultPR α β σ

full_name: DoResultBC.continue
code: /--
Auxiliary type used to compile `do` notation. It is an optimization of
`DoResultPRBC PEmpty PEmpty σ` to remove the impossible cases,
used when neither `pure` nor `return` are possible exit paths.
-/
inductive DoResultBC (σ : Type u) where
  /-- `break s` means that `break` was called, meaning that we should exit
  from the containing loop -/
  | break    : σ → DoResultBC σ
  /-- `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop -/
  | continue : σ → DoResultBC σ
goal: σ → DoResultBC σ

full_name: DoResultBC.break
code: /--
Auxiliary type used to compile `do` notation. It is an optimization of
`DoResultPRBC PEmpty PEmpty σ` to remove the impossible cases,
used when neither `pure` nor `return` are possible exit paths.
-/
inductive DoResultBC (σ : Type u) where
  /-- `break s` means that `break` was called, meaning that we should exit
  from the containing loop -/
  | break    : σ → DoResultBC σ
  /-- `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop -/
  | continue : σ → DoResultBC σ
goal: σ → DoResultBC σ

full_name: DoResultBC
code: /--
Auxiliary type used to compile `do` notation. It is an optimization of
`DoResultPRBC PEmpty PEmpty σ` to remove the impossible cases,
used when neither `pure` nor `return` are possible exit paths.
-/
inductive DoResultBC (σ : Type u) where
  /-- `break s` means that `break` was called, meaning that we should exit
  from the containing loop -/
  | break    : σ → DoResultBC σ
  /-- `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop -/
  | continue : σ → DoResultBC σ
goal: Type u

full_name: DoResultSBC.pureReturn
code: /--
Auxiliary type used to compile `do` notation. It is an optimization of
either `DoResultPRBC α PEmpty σ` or `DoResultPRBC PEmpty α σ` to remove the
impossible case, used when either `pure` or `return` is never used.
-/
inductive DoResultSBC (α σ : Type u) where
  /-- This encodes either `pure (a : α)` or `return (a : α)`:
  * `pure (a : α) s` means that the block exited normally with return value `a`
  * `return (b : β) s` means that the block exited via a `return b` early-exit command

  The one that is actually encoded depends on the context of use. -/
  | pureReturn : α → σ → DoResultSBC α σ
  /-- `break s` means that `break` was called, meaning that we should exit
  from the containing loop -/
  | break    : σ → DoResultSBC α σ
  /-- `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop -/
  | continue   : σ → DoResultSBC α σ
goal: α → σ → DoResultSBC α σ

full_name: DoResultSBC.break
code: /--
Auxiliary type used to compile `do` notation. It is an optimization of
either `DoResultPRBC α PEmpty σ` or `DoResultPRBC PEmpty α σ` to remove the
impossible case, used when either `pure` or `return` is never used.
-/
inductive DoResultSBC (α σ : Type u) where
  /-- This encodes either `pure (a : α)` or `return (a : α)`:
  * `pure (a : α) s` means that the block exited normally with return value `a`
  * `return (b : β) s` means that the block exited via a `return b` early-exit command

  The one that is actually encoded depends on the context of use. -/
  | pureReturn : α → σ → DoResultSBC α σ
  /-- `break s` means that `break` was called, meaning that we should exit
  from the containing loop -/
  | break    : σ → DoResultSBC α σ
  /-- `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop -/
  | continue   : σ → DoResultSBC α σ
goal: σ → DoResultSBC α σ

full_name: DoResultSBC
code: /--
Auxiliary type used to compile `do` notation. It is an optimization of
either `DoResultPRBC α PEmpty σ` or `DoResultPRBC PEmpty α σ` to remove the
impossible case, used when either `pure` or `return` is never used.
-/
inductive DoResultSBC (α σ : Type u) where
  /-- This encodes either `pure (a : α)` or `return (a : α)`:
  * `pure (a : α) s` means that the block exited normally with return value `a`
  * `return (b : β) s` means that the block exited via a `return b` early-exit command

  The one that is actually encoded depends on the context of use. -/
  | pureReturn : α → σ → DoResultSBC α σ
  /-- `break s` means that `break` was called, meaning that we should exit
  from the containing loop -/
  | break    : σ → DoResultSBC α σ
  /-- `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop -/
  | continue   : σ → DoResultSBC α σ
goal: Type u

full_name: DoResultSBC.continue
code: /--
Auxiliary type used to compile `do` notation. It is an optimization of
either `DoResultPRBC α PEmpty σ` or `DoResultPRBC PEmpty α σ` to remove the
impossible case, used when either `pure` or `return` is never used.
-/
inductive DoResultSBC (α σ : Type u) where
  /-- This encodes either `pure (a : α)` or `return (a : α)`:
  * `pure (a : α) s` means that the block exited normally with return value `a`
  * `return (b : β) s` means that the block exited via a `return b` early-exit command

  The one that is actually encoded depends on the context of use. -/
  | pureReturn : α → σ → DoResultSBC α σ
  /-- `break s` means that `break` was called, meaning that we should exit
  from the containing loop -/
  | break    : σ → DoResultSBC α σ
  /-- `continue s` means that `continue` was called, meaning that we should continue
  to the next iteration of the containing loop -/
  | continue   : σ → DoResultSBC α σ
goal: σ → DoResultSBC α σ

full_name: HasEquiv
code: /-- `HasEquiv α` is the typeclass which supports the notation `x ≈ y` where `x y : α`.-/
class HasEquiv (α : Sort u) where
  /-- `x ≈ y` says that `x` and `y` are equivalent. Because this is a typeclass,
  the notion of equivalence is type-dependent. -/
  Equiv : α → α → Sort v
goal: Sort (max u (v + 1))

full_name: HasEquiv.Equiv
code: /-- `HasEquiv α` is the typeclass which supports the notation `x ≈ y` where `x y : α`.-/
class HasEquiv (α : Sort u) where
  /-- `x ≈ y` says that `x` and `y` are equivalent. Because this is a typeclass,
  the notion of equivalence is type-dependent. -/
  Equiv : α → α → Sort v
goal: α → α → Sort v

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_HasEquiv_Equiv_1»
code: @[inherit_doc] infix:50 " ≈ "  => HasEquiv.Equiv
goal: Lean.PrettyPrinter.Unexpander

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term_≈__1»
code: @[inherit_doc] infix:50 " ≈ "  => HasEquiv.Equiv
goal: Lean.Macro

full_name: HasSubset
code: /-- Notation type class for the subset relation `⊆`. -/
class HasSubset (α : Type u) where
  /-- Subset relation: `a ⊆ b`  -/
  Subset : α → α → Prop
goal: Type u

full_name: HasSubset.Subset
code: /-- Notation type class for the subset relation `⊆`. -/
class HasSubset (α : Type u) where
  /-- Subset relation: `a ⊆ b`  -/
  Subset : α → α → Prop
goal: α → α → Prop

full_name: HasSSubset
code: /-- Notation type class for the strict subset relation `⊂`. -/
class HasSSubset (α : Type u) where
  /-- Strict subset relation: `a ⊂ b`  -/
  SSubset : α → α → Prop
goal: Type u

full_name: HasSSubset.SSubset
code: /-- Notation type class for the strict subset relation `⊂`. -/
class HasSSubset (α : Type u) where
  /-- Strict subset relation: `a ⊂ b`  -/
  SSubset : α → α → Prop
goal: α → α → Prop

full_name: Superset
code: /-- Superset relation: `a ⊇ b`  -/
abbrev Superset [HasSubset α] (a b : α) 
goal: Prop

full_name: SSuperset
code: /-- Strict superset relation: `a ⊃ b`  -/
abbrev SSuperset [HasSSubset α] (a b : α) 
goal: Prop

full_name: Union.union
code: /-- Notation type class for the union operation `∪`. -/
class Union (α : Type u) where
  /-- `a ∪ b` is the union of`a` and `b`. -/
  union : α → α → α
goal: α → α → α

full_name: Union
code: /-- Notation type class for the union operation `∪`. -/
class Union (α : Type u) where
  /-- `a ∪ b` is the union of`a` and `b`. -/
  union : α → α → α
goal: Type u

full_name: Inter
code: /-- Notation type class for the intersection operation `∩`. -/
class Inter (α : Type u) where
  /-- `a ∩ b` is the intersection of`a` and `b`. -/
  inter : α → α → α
goal: Type u

full_name: Inter.inter
code: /-- Notation type class for the intersection operation `∩`. -/
class Inter (α : Type u) where
  /-- `a ∩ b` is the intersection of`a` and `b`. -/
  inter : α → α → α
goal: α → α → α

full_name: SDiff
code: /-- Notation type class for the set difference `\`. -/
class SDiff (α : Type u) where
  /--
  `a \ b` is the set difference of `a` and `b`,
  consisting of all elements in `a` that are not in `b`.
  -/
  sdiff : α → α → α
goal: Type u

full_name: SDiff.sdiff
code: /-- Notation type class for the set difference `\`. -/
class SDiff (α : Type u) where
  /--
  `a \ b` is the set difference of `a` and `b`,
  consisting of all elements in `a` that are not in `b`.
  -/
  sdiff : α → α → α
goal: α → α → α

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_HasSubset_Subset_1»
code: /-- Subset relation: `a ⊆ b`  -/
infix:50 " ⊆ " => Subset
goal: Lean.PrettyPrinter.Unexpander

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term_⊆__1»
code: /-- Subset relation: `a ⊆ b`  -/
infix:50 " ⊆ " => Subset
goal: Lean.Macro

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term_⊂__1»
code: /-- Strict subset relation: `a ⊂ b`  -/
infix:50 " ⊂ " => SSubset
goal: Lean.Macro

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_HasSSubset_SSubset_1»
code: /-- Strict subset relation: `a ⊂ b`  -/
infix:50 " ⊂ " => SSubset
goal: Lean.PrettyPrinter.Unexpander

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term_⊇__1»
code: /-- Superset relation: `a ⊇ b`  -/
infix:50 " ⊇ " => Superset
goal: Lean.Macro

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_Superset_1»
code: /-- Superset relation: `a ⊇ b`  -/
infix:50 " ⊇ " => Superset
goal: Lean.PrettyPrinter.Unexpander

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_SSuperset_1»
code: /-- Strict superset relation: `a ⊃ b`  -/
infix:50 " ⊃ " => SSuperset
goal: Lean.PrettyPrinter.Unexpander

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term_⊃__1»
code: /-- Strict superset relation: `a ⊃ b`  -/
infix:50 " ⊃ " => SSuperset
goal: Lean.Macro

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term_∪__1»
code: /-- `a ∪ b` is the union of`a` and `b`. -/
infixl:65 " ∪ " => Union.union
goal: Lean.Macro

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_Union_union_1»
code: /-- `a ∪ b` is the union of`a` and `b`. -/
infixl:65 " ∪ " => Union.union
goal: Lean.PrettyPrinter.Unexpander

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term_∩__1»
code: /-- `a ∩ b` is the intersection of`a` and `b`. -/
infixl:70 " ∩ " => Inter.inter
goal: Lean.Macro

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_Inter_inter_1»
code: /-- `a ∩ b` is the intersection of`a` and `b`. -/
infixl:70 " ∩ " => Inter.inter
goal: Lean.PrettyPrinter.Unexpander

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term_\__1»
code: /--
`a \ b` is the set difference of `a` and `b`,
consisting of all elements in `a` that are not in `b`.
-/
infix:70 " \\ " => SDiff.sdiff
goal: Lean.Macro

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_SDiff_sdiff_1»
code: /--
`a \ b` is the set difference of `a` and `b`,
consisting of all elements in `a` that are not in `b`.
-/
infix:70 " \\ " => SDiff.sdiff
goal: Lean.PrettyPrinter.Unexpander

full_name: EmptyCollection
code: /-- `EmptyCollection α` is the typeclass which supports the notation `∅`, also written as `{}`. -/
class EmptyCollection (α : Type u) where
  /-- `∅` or `{}` is the empty set or empty collection.
  It is supported by the `EmptyCollection` typeclass. -/
  emptyCollection : α
goal: Type u

full_name: EmptyCollection.emptyCollection
code: /-- `EmptyCollection α` is the typeclass which supports the notation `∅`, also written as `{}`. -/
class EmptyCollection (α : Type u) where
  /-- `∅` or `{}` is the empty set or empty collection.
  It is supported by the `EmptyCollection` typeclass. -/
  emptyCollection : α
goal: α

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_EmptyCollection_emptyCollection_1»
code: @[inherit_doc] notation "{" "}" => EmptyCollection.emptyCollection
goal: Lean.PrettyPrinter.Unexpander

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term{}_1»
code: @[inherit_doc] notation "{" "}" => EmptyCollection.emptyCollection
goal: Lean.Macro

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term∅_1»
code: @[inherit_doc] notation "∅"     => EmptyCollection.emptyCollection
goal: Lean.Macro

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_EmptyCollection_emptyCollection_2»
code: @[inherit_doc] notation "∅"     => EmptyCollection.emptyCollection
goal: Lean.PrettyPrinter.Unexpander

full_name: Insert
code: /--
Type class for the `insert` operation.
Used to implement the `{ a, b, c }` syntax.
-/
class Insert (α : outParam <| Type u) (γ : Type v) where
  /-- `insert x xs` inserts the element `x` into the collection `xs`. -/
  insert : α → γ → γ
goal: Type (max u v)

full_name: Insert.insert
code: /--
Type class for the `insert` operation.
Used to implement the `{ a, b, c }` syntax.
-/
class Insert (α : outParam <| Type u) (γ : Type v) where
  /-- `insert x xs` inserts the element `x` into the collection `xs`. -/
  insert : α → γ → γ
goal: α → γ → γ

full_name: Singleton
code: /--
Type class for the `singleton` operation.
Used to implement the `{ a, b, c }` syntax.
-/
class Singleton (α : outParam <| Type u) (β : Type v) where
  /-- `singleton x` is a collection with the single element `x` (notation: `{x}`). -/
  singleton : α → β
goal: Type (max u v)

full_name: Singleton.singleton
code: /--
Type class for the `singleton` operation.
Used to implement the `{ a, b, c }` syntax.
-/
class Singleton (α : outParam <| Type u) (β : Type v) where
  /-- `singleton x` is a collection with the single element `x` (notation: `{x}`). -/
  singleton : α → β
goal: α → β

full_name: LawfulSingleton
code: /-- `insert x ∅ = {x}` -/
class LawfulSingleton (α : Type u) (β : Type v) [EmptyCollection β] [Insert α β] [Singleton α β] :
    Prop where
  /-- `insert x ∅ = {x}` -/
  insert_emptyc_eq (x : α) : (insert x ∅ : β) = singleton x
goal: Prop

full_name: LawfulSingleton.insert_emptyc_eq
code: /-- `insert x ∅ = {x}` -/
class LawfulSingleton (α : Type u) (β : Type v) [EmptyCollection β] [Insert α β] [Singleton α β] :
    Prop where
  /-- `insert x ∅ = {x}` -/
  insert_emptyc_eq (x : α) : (insert x ∅ : β) = singleton x
goal: insert x ∅ = singleton x

full_name: Sep.sep
code: /-- Type class used to implement the notation `{ a ∈ c | p a }` -/
class Sep (α : outParam <| Type u) (γ : Type v) where
  /-- Computes `{ a ∈ c | p a }`. -/
  sep : (α → Prop) → γ → γ
goal: (α → Prop) → γ → γ

full_name: Sep
code: /-- Type class used to implement the notation `{ a ∈ c | p a }` -/
class Sep (α : outParam <| Type u) (γ : Type v) where
  /-- Computes `{ a ∈ c | p a }`. -/
  sep : (α → Prop) → γ → γ
goal: Type (max u v)

full_name: Task
code: /--
`Task α` is a primitive for asynchronous computation.
It represents a computation that will resolve to a value of type `α`,
possibly being computed on another thread. This is similar to `Future` in Scala,
`Promise` in Javascript, and `JoinHandle` in Rust.

The tasks have an overridden representation in the runtime.
-/
structure Task (α : Type u) : Type u where
  /-- `Task.pure (a : α)` constructs a task that is already resolved with value `a`. -/
  pure ::
  /-- If `task : Task α` then `task.get : α` blocks the current thread until the
  value is available, and then returns the result of the task. -/
  get : α
  deriving Inhabited, Nonempty
goal: Type u

full_name: instInhabitedTask
code: /--
`Task α` is a primitive for asynchronous computation.
It represents a computation that will resolve to a value of type `α`,
possibly being computed on another thread. This is similar to `Future` in Scala,
`Promise` in Javascript, and `JoinHandle` in Rust.

The tasks have an overridden representation in the runtime.
-/
structure Task (α : Type u) : Type u where
  /-- `Task.pure (a : α)` constructs a task that is already resolved with value `a`. -/
  pure ::
  /-- If `task : Task α` then `task.get : α` blocks the current thread until the
  value is available, and then returns the result of the task. -/
  get : α
  deriving Inhabited, Nonempty
goal: {a : Type u_1} → [inst : Inhabited a] → Inhabited (Task a)

full_name: instNonemptyTask
code: /--
`Task α` is a primitive for asynchronous computation.
It represents a computation that will resolve to a value of type `α`,
possibly being computed on another thread. This is similar to `Future` in Scala,
`Promise` in Javascript, and `JoinHandle` in Rust.

The tasks have an overridden representation in the runtime.
-/
structure Task (α : Type u) : Type u where
  /-- `Task.pure (a : α)` constructs a task that is already resolved with value `a`. -/
  pure ::
  /-- If `task : Task α` then `task.get : α` blocks the current thread until the
  value is available, and then returns the result of the task. -/
  get : α
  deriving Inhabited, Nonempty
goal: ∀ {α : Type u_1} [inst : Nonempty α], Nonempty (Task α)

full_name: Task.get
code: /--
`Task α` is a primitive for asynchronous computation.
It represents a computation that will resolve to a value of type `α`,
possibly being computed on another thread. This is similar to `Future` in Scala,
`Promise` in Javascript, and `JoinHandle` in Rust.

The tasks have an overridden representation in the runtime.
-/
structure Task (α : Type u) : Type u where
  /-- `Task.pure (a : α)` constructs a task that is already resolved with value `a`. -/
  pure ::
  /-- If `task : Task α` then `task.get : α` blocks the current thread until the
  value is available, and then returns the result of the task. -/
  get : α
  deriving Inhabited, Nonempty
goal: α

full_name: Task.pure
code: /--
`Task α` is a primitive for asynchronous computation.
It represents a computation that will resolve to a value of type `α`,
possibly being computed on another thread. This is similar to `Future` in Scala,
`Promise` in Javascript, and `JoinHandle` in Rust.

The tasks have an overridden representation in the runtime.
-/
structure Task (α : Type u) : Type u where
  /-- `Task.pure (a : α)` constructs a task that is already resolved with value `a`. -/
  pure ::
  /-- If `task : Task α` then `task.get : α` blocks the current thread until the
  value is available, and then returns the result of the task. -/
  get : α
  deriving Inhabited, Nonempty
goal: Task α

full_name: Task.Priority
code: /-- Task priority. Tasks with higher priority will always be scheduled before ones with lower priority. -/
abbrev Priority 
goal: Type

full_name: Task.Priority.default
code: /-- The default priority for spawned tasks, also the lowest priority: `0`. -/
def Priority.default : Priority 
goal: Task.Priority

full_name: Task.Priority.max
code: /--
The highest regular priority for spawned tasks: `8`.

Spawning a task with a priority higher than `Task.Priority.max` is not an error but
will spawn a dedicated worker for the task, see `Task.Priority.dedicated`.
Regular priority tasks are placed in a thread pool and worked on according to the priority order.
-/
-- see `LEAN_MAX_PRIO`
def Priority.max : Priority 
goal: Task.Priority

full_name: Task.Priority.dedicated
code: /--
Any priority higher than `Task.Priority.max` will result in the task being scheduled
immediately on a dedicated thread. This is particularly useful for long-running and/or
I/O-bound tasks since Lean will by default allocate no more non-dedicated workers
than the number of cores to reduce context switches.
-/
def Priority.dedicated : Priority 
goal: Task.Priority

full_name: Task.spawn
code: /--
`spawn fn : Task α` constructs and immediately launches a new task for
evaluating the function `fn () : α` asynchronously.

`prio`, if provided, is the priority of the task.
-/
@[noinline, extern "lean_task_spawn"]
protected def spawn {α : Type u} (fn : Unit → α) (prio := Priority.default) : Task α 
goal: Task α

full_name: Task.map
code: /--
`map f x` maps function `f` over the task `x`: that is, it constructs
(and immediately launches) a new task which will wait for the value of `x` to
be available and then calls `f` on the result.

`prio`, if provided, is the priority of the task.
If `sync` is set to true, `f` is executed on the current thread if `x` has already finished.
-/
@[noinline, extern "lean_task_map"]
protected def map (f : α → β) (x : Task α) (prio := Priority.default) (sync := false) : Task β 
goal: Task β

full_name: Task.bind
code: /--
`bind x f` does a monad "bind" operation on the task `x` with function `f`:
that is, it constructs (and immediately launches) a new task which will wait
for the value of `x` to be available and then calls `f` on the result,
resulting in a new task which is then run for a result.

`prio`, if provided, is the priority of the task.
If `sync` is set to true, `f` is executed on the current thread if `x` has already finished.
-/
@[noinline, extern "lean_task_bind"]
protected def bind (x : Task α) (f : α → Task β) (prio := Priority.default) (sync := false) :
    Task β 
goal: Task β

full_name: NonScalar
code: /--
`NonScalar` is a type that is not a scalar value in our runtime.
It is used as a stand-in for an arbitrary boxed value to avoid excessive
monomorphization, and it is only created using `unsafeCast`. It is somewhat
analogous to C `void*` in usage, but the type itself is not special.
-/
structure NonScalar where
  /-- You should not use this function -/ mk ::
  /-- You should not use this function -/ val : Nat
goal: Type

full_name: NonScalar.val
code: /--
`NonScalar` is a type that is not a scalar value in our runtime.
It is used as a stand-in for an arbitrary boxed value to avoid excessive
monomorphization, and it is only created using `unsafeCast`. It is somewhat
analogous to C `void*` in usage, but the type itself is not special.
-/
structure NonScalar where
  /-- You should not use this function -/ mk ::
  /-- You should not use this function -/ val : Nat
goal: Nat

full_name: NonScalar.mk
code: /--
`NonScalar` is a type that is not a scalar value in our runtime.
It is used as a stand-in for an arbitrary boxed value to avoid excessive
monomorphization, and it is only created using `unsafeCast`. It is somewhat
analogous to C `void*` in usage, but the type itself is not special.
-/
structure NonScalar where
  /-- You should not use this function -/ mk ::
  /-- You should not use this function -/ val : Nat
goal: NonScalar

full_name: PNonScalar.mk
code: /--
`PNonScalar` is a type that is not a scalar value in our runtime.
It is used as a stand-in for an arbitrary boxed value to avoid excessive
monomorphization, and it is only created using `unsafeCast`. It is somewhat
analogous to C `void*` in usage, but the type itself is not special.

This is the universe-polymorphic version of `PNonScalar`; it is preferred to use
`NonScalar` instead where applicable.
-/
inductive PNonScalar : Type u where
  /-- You should not use this function -/
  | mk (v : Nat) : PNonScalar
goal: PNonScalar

full_name: PNonScalar
code: /--
`PNonScalar` is a type that is not a scalar value in our runtime.
It is used as a stand-in for an arbitrary boxed value to avoid excessive
monomorphization, and it is only created using `unsafeCast`. It is somewhat
analogous to C `void*` in usage, but the type itself is not special.

This is the universe-polymorphic version of `PNonScalar`; it is preferred to use
`NonScalar` instead where applicable.
-/
inductive PNonScalar : Type u where
  /-- You should not use this function -/
  | mk (v : Nat) : PNonScalar
goal: Type u

full_name: Nat.add_zero
code: @[simp] protected theorem Nat.add_zero (n : Nat) : n + 0 = n 
goal: n + 0 = n

full_name: optParam_eq
code: theorem optParam_eq (α : Sort u) (default : α) : optParam α default = α 
goal: optParam α default = α

full_name: strictOr
code: /--
`strictOr` is the same as `or`, but it does not use short-circuit evaluation semantics:
both sides are evaluated, even if the first value is `true`.
-/
@[extern "lean_strict_or"] def strictOr  (b₁ b₂ : Bool) 
goal: Bool

full_name: strictAnd
code: /--
`strictAnd` is the same as `and`, but it does not use short-circuit evaluation semantics:
both sides are evaluated, even if the first value is `false`.
-/
@[extern "lean_strict_and"] def strictAnd (b₁ b₂ : Bool) 
goal: Bool

full_name: bne
code: /--
`x != y` is boolean not-equal. It is the negation of `x == y` which is supplied by
the `BEq` typeclass.

Unlike `x ≠ y` (which is notation for `Ne x y`), this is `Bool` valued instead of
`Prop` valued. It is mainly intended for programming applications.
-/
@[inline] def bne {α : Type u} [BEq α] (a b : α) : Bool 
goal: Bool

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_bne_1»
code: @[inherit_doc] infix:50 " != " => bne
goal: Lean.PrettyPrinter.Unexpander

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term_!=__1»
code: @[inherit_doc] infix:50 " != " => bne
goal: Lean.Macro

full_name: LawfulBEq
code: /--
`LawfulBEq α` is a typeclass which asserts that the `BEq α` implementation
(which supplies the `a == b` notation) coincides with logical equality `a = b`.
In other words, `a == b` implies `a = b`, and `a == a` is true.
-/
class LawfulBEq (α : Type u) [BEq α] : Prop where
  /-- If `a == b` evaluates to `true`, then `a` and `b` are equal in the logic. -/
  eq_of_beq : {a b : α} → a == b → a = b
  /-- `==` is reflexive, that is, `(a == a) = true`. -/
  protected rfl : {a : α} → a == a
goal: Prop

full_name: LawfulBEq.rfl
code: /--
`LawfulBEq α` is a typeclass which asserts that the `BEq α` implementation
(which supplies the `a == b` notation) coincides with logical equality `a = b`.
In other words, `a == b` implies `a = b`, and `a == a` is true.
-/
class LawfulBEq (α : Type u) [BEq α] : Prop where
  /-- If `a == b` evaluates to `true`, then `a` and `b` are equal in the logic. -/
  eq_of_beq : {a b : α} → a == b → a = b
  /-- `==` is reflexive, that is, `(a == a) = true`. -/
  protected rfl : {a : α} → a == a
goal: (a == a) = true

full_name: LawfulBEq.eq_of_beq
code: /--
`LawfulBEq α` is a typeclass which asserts that the `BEq α` implementation
(which supplies the `a == b` notation) coincides with logical equality `a = b`.
In other words, `a == b` implies `a = b`, and `a == a` is true.
-/
class LawfulBEq (α : Type u) [BEq α] : Prop where
  /-- If `a == b` evaluates to `true`, then `a` and `b` are equal in the logic. -/
  eq_of_beq : {a b : α} → a == b → a = b
  /-- `==` is reflexive, that is, `(a == a) = true`. -/
  protected rfl : {a : α} → a == a
goal: (a == b) = true → a = b

full_name: instLawfulBEqBool
code: instance : LawfulBEq Bool 
goal: LawfulBEq Bool

full_name: instLawfulBEq
code: instance [DecidableEq α] : LawfulBEq α 
goal: LawfulBEq α

full_name: instLawfulBEqChar
code: instance : LawfulBEq Char 
goal: LawfulBEq Char

full_name: instLawfulBEqString
code: instance : LawfulBEq String 
goal: LawfulBEq String

full_name: trivial
code: @[inherit_doc True.intro] theorem trivial : True 
goal: True

full_name: mt
code: theorem mt {a b : Prop} (h₁ : a → b) (h₂ : ¬b) : ¬a 
goal: ¬a

full_name: not_false
code: theorem not_false : ¬False 
goal: ¬False

full_name: not_not_intro
code: theorem not_not_intro {p : Prop} (h : p) : ¬ ¬ p 
goal: ¬¬p

full_name: proof_irrel
code: theorem proof_irrel {a : Prop} (h₁ h₂ : a) : h₁ = h₂ 
goal: h₁ = h₂

full_name: Eq.mp
code: /--
If `h : α = β` is a proof of type equality, then `h.mp : α → β` is the induced
"cast" operation, mapping elements of `α` to elements of `β`.

You can prove theorems about the resulting element by induction on `h`, since
`rfl.mp` is definitionally the identity function.
-/
@[macro_inline] def Eq.mp {α β : Sort u} (h : α = β) (a : α) : β 
goal: β

full_name: Eq.mpr
code: /--
If `h : α = β` is a proof of type equality, then `h.mpr : β → α` is the induced
"cast" operation in the reverse direction, mapping elements of `β` to elements of `α`.

You can prove theorems about the resulting element by induction on `h`, since
`rfl.mpr` is definitionally the identity function.
-/
@[macro_inline] def Eq.mpr {α β : Sort u} (h : α = β) (b : β) : α 
goal: α

full_name: Eq.substr
code: @[elab_as_elim]
theorem Eq.substr {α : Sort u} {p : α → Prop} {a b : α} (h₁ : b = a) (h₂ : p a) : p b 
goal: p b

full_name: cast_eq
code: @[simp] theorem cast_eq {α : Sort u} (h : α = α) (a : α) : cast h a = a 
goal: cast h a = a

full_name: Ne
code: /--
`a ≠ b`, or `Ne a b` is defined as `¬ (a = b)` or `a = b → False`,
and asserts that `a` and `b` are not equal.
-/
@[reducible] def Ne {α : Sort u} (a b : α) 
goal: Prop

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___unexpand_Ne_1»
code: @[inherit_doc] infix:50 " ≠ "  => Ne
goal: Lean.PrettyPrinter.Unexpander

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_term_≠__1»
code: @[inherit_doc] infix:50 " ≠ "  => Ne
goal: Lean.Macro

full_name: Ne.intro
code: theorem Ne.intro (h : a = b → False) : a ≠ b 
goal: a ≠ b

full_name: Ne.elim
code: theorem Ne.elim (h : a ≠ b) : a = b → False 
goal: a = b → False

full_name: Ne.irrefl
code: theorem Ne.irrefl (h : a ≠ a) : False 
goal: False

full_name: Ne.symm
code: theorem Ne.symm (h : a ≠ b) : b ≠ a 
goal: b ≠ a

full_name: ne_comm
code: theorem ne_comm {α} {a b : α} : a ≠ b ↔ b ≠ a 
goal: a ≠ b ↔ b ≠ a

full_name: false_of_ne
code: theorem false_of_ne : a ≠ a → False 
goal: a ≠ a → False

full_name: ne_false_of_self
code: theorem ne_false_of_self : p → p ≠ False 
goal: p → p ≠ False

full_name: ne_true_of_not
code: theorem ne_true_of_not : ¬p → p ≠ True 
goal: ¬p → p ≠ True

full_name: true_ne_false
code: theorem true_ne_false : ¬True = False 
goal: ¬True = False

full_name: false_ne_true
code: theorem false_ne_true : False ≠ True 
goal: False ≠ True

full_name: Bool.of_not_eq_true
code: theorem Bool.of_not_eq_true : {b : Bool} → ¬ (b = true) → b = false
  
goal: ¬b = true → b = false

full_name: Bool.of_not_eq_false
code: theorem Bool.of_not_eq_false : {b : Bool} → ¬ (b = false) → b = true
  
goal: ¬b = false → b = true

full_name: ne_of_beq_false
code: theorem ne_of_beq_false [BEq α] [LawfulBEq α] {a b : α} (h : (a == b) = false) : a ≠ b 
goal: a ≠ b

full_name: beq_false_of_ne
code: theorem beq_false_of_ne [BEq α] [LawfulBEq α] {a b : α} (h : a ≠ b) : (a == b) = false 
goal: (a == b) = false

full_name: HEq.ndrec
code: /-- Non-dependent recursor for `HEq` -/
noncomputable def HEq.ndrec.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} → β → Sort u1} (m : motive a) {β : Sort u2} {b : β} (h : HEq a b) : motive b 
goal: motive b

full_name: HEq.ndrecOn
code: /-- `HEq.ndrec` variant -/
noncomputable def HEq.ndrecOn.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} → β → Sort u1} {β : Sort u2} {b : β} (h : HEq a b) (m : motive a) : motive b 
goal: motive b

full_name: HEq.elim
code: /-- `HEq.ndrec` variant -/
noncomputable def HEq.elim {α : Sort u} {a : α} {p : α → Sort v} {b : α} (h₁ : HEq a b) (h₂ : p a) : p b 
goal: p b

full_name: HEq.subst
code: theorem HEq.subst {p : (T : Sort u) → T → Prop} (h₁ : HEq a b) (h₂ : p α a) : p β b 
goal: p β b

full_name: HEq.symm
code: theorem HEq.symm (h : HEq a b) : HEq b a 
goal: HEq b a

full_name: heq_of_eq
code: theorem heq_of_eq (h : a = a') : HEq a a' 
goal: HEq a a'

full_name: HEq.trans
code: theorem HEq.trans (h₁ : HEq a b) (h₂ : HEq b c) : HEq a c 
goal: HEq a c

full_name: heq_of_heq_of_eq
code: theorem heq_of_heq_of_eq (h₁ : HEq a b) (h₂ : b = b') : HEq a b' 
goal: HEq a b'

full_name: heq_of_eq_of_heq
code: theorem heq_of_eq_of_heq (h₁ : a = a') (h₂ : HEq a' b) : HEq a b 
goal: HEq a b

full_name: type_eq_of_heq
code: theorem type_eq_of_heq (h : HEq a b) : α = β 
goal: α = β

full_name: eqRec_heq
code: theorem eqRec_heq {α : Sort u} {φ : α → Sort v} {a a' : α} : (h : a = a') → (p : φ a) → HEq (Eq.recOn (motive := fun x _ => φ x) h p) p
  
goal: HEq (Eq.recOn h p) p

full_name: heq_of_eqRec_eq
code: theorem heq_of_eqRec_eq {α β : Sort u} {a : α} {b : β} (h₁ : α = β) (h₂ : Eq.rec (motive := fun α _ => α) a h₁ = b) : HEq a b 
goal: HEq a b

full_name: cast_heq
code: theorem cast_heq {α β : Sort u} : (h : α = β) → (a : α) → HEq (cast h a) a
  
goal: HEq (cast h a) a

full_name: iff_iff_implies_and_implies
code: theorem iff_iff_implies_and_implies (a b : Prop) : (a ↔ b) ↔ (a → b) ∧ (b → a) 
goal: (a ↔ b) ↔ (a → b) ∧ (b → a)

full_name: Iff.refl
code: theorem Iff.refl (a : Prop) : a ↔ a 
goal: a ↔ a

full_name: Iff.rfl
code: protected theorem Iff.rfl {a : Prop} : a ↔ a 
goal: a ↔ a

full_name: «_aux_.lake_packages_lean4_src_lean_Init_Core___macroRules_Lean_Parser_Tactic_tacticRfl_1»
code: macro_rules | `(tactic| rfl) => `(tactic| exact Iff.rfl)
goal: Lean.Macro

full_name: Iff.of_eq
code: theorem Iff.of_eq (h : a = b) : a ↔ b 
goal: a ↔ b

full_name: Iff.trans
code: theorem Iff.trans (h₁ : a ↔ b) (h₂ : b ↔ c) : a ↔ c 
goal: a ↔ c

full_name: instTransIff
code: instance : Trans Iff Iff Iff 
goal: Trans Iff Iff Iff

full_name: Eq.comm
code: theorem Eq.comm {a b : α} : a = b ↔ b = a 
goal: a = b ↔ b = a

full_name: eq_comm
code: theorem eq_comm {a b : α} : a = b ↔ b = a 
goal: a = b ↔ b = a

full_name: Iff.symm
code: theorem Iff.symm (h : a ↔ b) : b ↔ a 
goal: b ↔ a

full_name: Iff.comm
code: theorem Iff.comm: (a ↔ b) ↔ (b ↔ a) 
goal: (a ↔ b) ↔ (b ↔ a)

full_name: iff_comm
code: theorem iff_comm : (a ↔ b) ↔ (b ↔ a) 
goal: (a ↔ b) ↔ (b ↔ a)

full_name: And.symm
code: theorem And.symm : a ∧ b → b ∧ a 
goal: a ∧ b → b ∧ a

full_name: And.comm
code: theorem And.comm : a ∧ b ↔ b ∧ a 
goal: a ∧ b ↔ b ∧ a

full_name: and_comm
code: theorem and_comm : a ∧ b ↔ b ∧ a 
goal: a ∧ b ↔ b ∧ a

full_name: Or.symm
code: theorem Or.symm : a ∨ b → b ∨ a 
goal: a ∨ b → b ∨ a

full_name: Or.comm
code: theorem Or.comm : a ∨ b ↔ b ∨ a 
goal: a ∨ b ↔ b ∨ a

full_name: or_comm
code: theorem or_comm : a ∨ b ↔ b ∨ a 
goal: a ∨ b ↔ b ∨ a

full_name: Exists.elim
code: theorem Exists.elim {α : Sort u} {p : α → Prop} {b : Prop}
   (h₁ : Exists (fun x => p x)) (h₂ : ∀ (a : α), p a → b) : b 
goal: b

full_name: decide_true_eq_true
code: theorem decide_true_eq_true (h : Decidable True) : @decide True h = true 
goal: decide True = true

full_name: decide_false_eq_false
code: theorem decide_false_eq_false (h : Decidable False) : @decide False h = false 
goal: decide False = false

full_name: toBoolUsing
code: /-- Similar to `decide`, but uses an explicit instance -/
@[inline] def toBoolUsing {p : Prop} (d : Decidable p) : Bool 
goal: Bool

full_name: toBoolUsing_eq_true
code: theorem toBoolUsing_eq_true {p : Prop} (d : Decidable p) (h : p) : toBoolUsing d = true 
goal: toBoolUsing d = true

full_name: ofBoolUsing_eq_true
code: theorem ofBoolUsing_eq_true {p : Prop} {d : Decidable p} (h : toBoolUsing d = true) : p 
goal: p

full_name: ofBoolUsing_eq_false
code: theorem ofBoolUsing_eq_false {p : Prop} {d : Decidable p} (h : toBoolUsing d = false) : ¬ p 
goal: ¬p

full_name: «instDecidableTrue_.lake»
code: instance : Decidable True 
goal: Decidable True

full_name: «instDecidableFalse_.lake»
code: instance : Decidable False 
goal: Decidable False

full_name: Decidable.byCases
code: /--
Synonym for `dite` (dependent if-then-else). We can construct an element `q`
(of any sort, not just a proposition) by cases on whether `p` is true or false,
provided `p` is decidable.
-/
@[macro_inline] def byCases {q : Sort u} [dec : Decidable p] (h1 : p → q) (h2 : ¬p → q) : q 
goal: q

full_name: Decidable.em
code: theorem em (p : Prop) [Decidable p] : p ∨ ¬p 
goal: p ∨ ¬p

full_name: Decidable.byContradiction
code: theorem byContradiction [dec : Decidable p] (h : ¬p → False) : p 
goal: p

full_name: Decidable.of_not_not
code: theorem of_not_not [Decidable p] : ¬ ¬ p → p 
goal: ¬¬p → p

full_name: Decidable.not_and_iff_or_not
code: theorem not_and_iff_or_not (p q : Prop) [d₁ : Decidable p] [d₂ : Decidable q] : ¬ (p ∧ q) ↔ ¬ p ∨ ¬ q 
goal: ¬(p ∧ q) ↔ ¬p ∨ ¬q

full_name: decidable_of_decidable_of_iff
code: /-- Transfer a decidability proof across an equivalence of propositions. -/
@[inline] def decidable_of_decidable_of_iff [Decidable p] (h : p ↔ q) : Decidable q 
goal: Decidable q

full_name: decidable_of_decidable_of_eq
code: /-- Transfer a decidability proof across an equality of propositions. -/
@[inline] def decidable_of_decidable_of_eq [Decidable p] (h : p = q) : Decidable q 
goal: Decidable q

full_name: «instDecidableForall_.lake»
code: @[macro_inline] instance {p q} [Decidable p] [Decidable q] : Decidable (p → q) 
goal: Decidable (p → q)

full_name: instDecidableIff
code: instance {p q} [Decidable p] [Decidable q] : Decidable (p ↔ q) 
goal: Decidable (p ↔ q)

full_name: if_pos
code: theorem if_pos {c : Prop} {h : Decidable c} (hc : c) {α : Sort u} {t e : α} : (ite c t e) = t 
goal: ite c t e = t

full_name: if_neg
code: theorem if_neg {c : Prop} {h : Decidable c} (hnc : ¬c) {α : Sort u} {t e : α} : (ite c t e) = e 
goal: ite c t e = e

full_name: iteInduction
code: /-- Split an if-then-else into cases. The `split` tactic is generally easier to use than this theorem. -/
def iteInduction {c} [inst : Decidable c] {motive : α → Sort _} {t e : α}
    (hpos : c → motive t) (hneg : ¬c → motive e) : motive (ite c t e) 
goal: motive (ite c t e)

full_name: dif_pos
code: theorem dif_pos {c : Prop} {h : Decidable c} (hc : c) {α : Sort u} {t : c → α} {e : ¬ c → α} : (dite c t e) = t hc 
goal: dite c t e = t hc

full_name: dif_neg
code: theorem dif_neg {c : Prop} {h : Decidable c} (hnc : ¬c) {α : Sort u} {t : c → α} {e : ¬ c → α} : (dite c t e) = e hnc 
goal: dite c t e = e hnc

full_name: dif_eq_if
code: theorem dif_eq_if (c : Prop) {h : Decidable c} {α : Sort u} (t : α) (e : α) : dite c (fun _ => t) (fun _ => e) = ite c t e 
goal: (if x : c then t else e) = ite c t e

full_name: «instDecidableIte_.lake»
code: instance {c t e : Prop} [dC : Decidable c] [dT : Decidable t] [dE : Decidable e] : Decidable (if c then t else e)  
goal: Decidable (ite c t e)

full_name: «instDecidableDite_.lake»
code: instance {c : Prop} {t : c → Prop} {e : ¬c → Prop} [dC : Decidable c] [dT : ∀ h, Decidable (t h)] [dE : ∀ h, Decidable (e h)] : Decidable (if h : c then t h else e h)  
goal: Decidable (if h : c then t h else e h)

full_name: noConfusionTypeEnum
code: /-- Auxiliary definition for generating compact `noConfusion` for enumeration types -/
abbrev noConfusionTypeEnum {α : Sort u} {β : Sort v} [inst : DecidableEq β] (f : α → β) (P : Sort w) (x y : α) : Sort w 
goal: Sort w

full_name: noConfusionEnum
code: /-- Auxiliary definition for generating compact `noConfusion` for enumeration types -/
abbrev noConfusionEnum {α : Sort u} {β : Sort v} [inst : DecidableEq β] (f : α → β) {P : Sort w} {x y : α} (h : x = y) : noConfusionTypeEnum f P x y 
goal: noConfusionTypeEnum f P x y

full_name: «instInhabitedProp_.lake»
code: instance : Inhabited Prop 
goal: Inhabited Prop

full_name: instInhabitedNonScalar
code: Inhabited
goal: Inhabited NonScalar

full_name: «instInhabitedTrue_.lake»
code: Inhabited
goal: Inhabited True

full_name: instInhabitedForInStep_1
code: Inhabited
goal: {a : Type u_1} → [inst : Inhabited a] → Inhabited (ForInStep a)

full_name: instInhabitedPNonScalar
code: Inhabited
goal: Inhabited PNonScalar

full_name: nonempty_of_exists
code: theorem nonempty_of_exists {α : Sort u} {p : α → Prop} : Exists (fun x => p x) → Nonempty α
  
goal: (Exists fun x => p x) → Nonempty α

full_name: Subsingleton
code: /--
A "subsingleton" is a type with at most one element.
In other words, it is either empty, or has a unique element.
All propositions are subsingletons because of proof irrelevance, but some other types
are subsingletons as well and they inherit many of the same properties as propositions.
`Subsingleton α` is a typeclass, so it is usually used as an implicit argument and
inferred by typeclass inference.
-/
class Subsingleton (α : Sort u) : Prop where
  /-- Construct a proof that `α` is a subsingleton by showing that any two elements are equal. -/
  intro ::
  /-- Any two elements of a subsingleton are equal. -/
  allEq : (a b : α) → a = b
goal: Prop

full_name: Subsingleton.allEq
code: /--
A "subsingleton" is a type with at most one element.
In other words, it is either empty, or has a unique element.
All propositions are subsingletons because of proof irrelevance, but some other types
are subsingletons as well and they inherit many of the same properties as propositions.
`Subsingleton α` is a typeclass, so it is usually used as an implicit argument and
inferred by typeclass inference.
-/
class Subsingleton (α : Sort u) : Prop where
  /-- Construct a proof that `α` is a subsingleton by showing that any two elements are equal. -/
  intro ::
  /-- Any two elements of a subsingleton are equal. -/
  allEq : (a b : α) → a = b
goal: a = b

full_name: Subsingleton.intro
code: /--
A "subsingleton" is a type with at most one element.
In other words, it is either empty, or has a unique element.
All propositions are subsingletons because of proof irrelevance, but some other types
are subsingletons as well and they inherit many of the same properties as propositions.
`Subsingleton α` is a typeclass, so it is usually used as an implicit argument and
inferred by typeclass inference.
-/
class Subsingleton (α : Sort u) : Prop where
  /-- Construct a proof that `α` is a subsingleton by showing that any two elements are equal. -/
  intro ::
  /-- Any two elements of a subsingleton are equal. -/
  allEq : (a b : α) → a = b
goal: Subsingleton α

full_name: Subsingleton.elim
code: protected theorem Subsingleton.elim {α : Sort u} [h : Subsingleton α] : (a b : α) → a = b 
goal: a = b

full_name: Subsingleton.helim
code: protected theorem Subsingleton.helim {α β : Sort u} [h₁ : Subsingleton α] (h₂ : α = β) (a : α) (b : β) : HEq a b 
goal: HEq a b

full_name: instSubsingleton
code: instance (p : Prop) : Subsingleton p 
goal: Subsingleton p

full_name: instSubsingletonEmpty
code: instance : Subsingleton Empty  
goal: Subsingleton Empty

full_name: instSubsingletonPEmpty
code: instance : Subsingleton PEmpty 
goal: Subsingleton PEmpty

full_name: instSubsingletonProd
code: instance [Subsingleton α] [Subsingleton β] : Subsingleton (α × β) 
goal: Subsingleton (α × β)

full_name: instSubsingletonDecidable
code: instance (p : Prop) : Subsingleton (Decidable p) 
goal: Subsingleton (Decidable p)

full_name: recSubsingleton
code: theorem recSubsingleton
     {p : Prop} [h : Decidable p]
     {h₁ : p → Sort u}
     {h₂ : ¬p → Sort u}
     [h₃ : ∀ (h : p), Subsingleton (h₁ h)]
     [h₄ : ∀ (h : ¬p), Subsingleton (h₂ h)]
     : Subsingleton (h.casesOn h₂ h₁) 
goal: Subsingleton (Decidable.casesOn h h₂ h₁)

full_name: Equivalence.trans
code: /--
An equivalence relation `~ : α → α → Prop` is a relation that is:

* reflexive: `x ~ x`
* symmetric: `x ~ y` implies `y ~ x`
* transitive: `x ~ y` and `y ~ z` implies `x ~ z`

Equality is an equivalence relation, and equivalence relations share many of
the properties of equality. In particular, `Quot α r` is most well behaved
when `r` is an equivalence relation, and in this case we use `Quotient` instead.
-/
structure Equivalence {α : Sort u} (r : α → α → Prop) : Prop where
  /-- An equivalence relation is reflexive: `x ~ x` -/
  refl  : ∀ x, r x x
  /-- An equivalence relation is symmetric: `x ~ y` implies `y ~ x` -/
  symm  : ∀ {x y}, r x y → r y x
  /-- An equivalence relation is transitive: `x ~ y` and `y ~ z` implies `x ~ z` -/
  trans : ∀ {x y z}, r x y → r y z → r x z
goal: r x y → r y z → r x z

full_name: Equivalence.refl
code: /--
An equivalence relation `~ : α → α → Prop` is a relation that is:

* reflexive: `x ~ x`
* symmetric: `x ~ y` implies `y ~ x`
* transitive: `x ~ y` and `y ~ z` implies `x ~ z`

Equality is an equivalence relation, and equivalence relations share many of
the properties of equality. In particular, `Quot α r` is most well behaved
when `r` is an equivalence relation, and in this case we use `Quotient` instead.
-/
structure Equivalence {α : Sort u} (r : α → α → Prop) : Prop where
  /-- An equivalence relation is reflexive: `x ~ x` -/
  refl  : ∀ x, r x x
  /-- An equivalence relation is symmetric: `x ~ y` implies `y ~ x` -/
  symm  : ∀ {x y}, r x y → r y x
  /-- An equivalence relation is transitive: `x ~ y` and `y ~ z` implies `x ~ z` -/
  trans : ∀ {x y z}, r x y → r y z → r x z
goal: r x x

full_name: Equivalence.symm
code: /--
An equivalence relation `~ : α → α → Prop` is a relation that is:

* reflexive: `x ~ x`
* symmetric: `x ~ y` implies `y ~ x`
* transitive: `x ~ y` and `y ~ z` implies `x ~ z`

Equality is an equivalence relation, and equivalence relations share many of
the properties of equality. In particular, `Quot α r` is most well behaved
when `r` is an equivalence relation, and in this case we use `Quotient` instead.
-/
structure Equivalence {α : Sort u} (r : α → α → Prop) : Prop where
  /-- An equivalence relation is reflexive: `x ~ x` -/
  refl  : ∀ x, r x x
  /-- An equivalence relation is symmetric: `x ~ y` implies `y ~ x` -/
  symm  : ∀ {x y}, r x y → r y x
  /-- An equivalence relation is transitive: `x ~ y` and `y ~ z` implies `x ~ z` -/
  trans : ∀ {x y z}, r x y → r y z → r x z
goal: r x y → r y x

full_name: Equivalence
code: /--
An equivalence relation `~ : α → α → Prop` is a relation that is:

* reflexive: `x ~ x`
* symmetric: `x ~ y` implies `y ~ x`
* transitive: `x ~ y` and `y ~ z` implies `x ~ z`

Equality is an equivalence relation, and equivalence relations share many of
the properties of equality. In particular, `Quot α r` is most well behaved
when `r` is an equivalence relation, and in this case we use `Quotient` instead.
-/
structure Equivalence {α : Sort u} (r : α → α → Prop) : Prop where
  /-- An equivalence relation is reflexive: `x ~ x` -/
  refl  : ∀ x, r x x
  /-- An equivalence relation is symmetric: `x ~ y` implies `y ~ x` -/
  symm  : ∀ {x y}, r x y → r y x
  /-- An equivalence relation is transitive: `x ~ y` and `y ~ z` implies `x ~ z` -/
  trans : ∀ {x y z}, r x y → r y z → r x z
goal: Prop

full_name: emptyRelation
code: /-- The empty relation is the relation on `α` which is always `False`. -/
def emptyRelation {α : Sort u} (_ _ : α) : Prop 
goal: α → α → Prop

full_name: Subrelation
code: /--
`Subrelation q r` means that `q ⊆ r` or `∀ x y, q x y → r x y`.
It is the analogue of the subset relation on relations.
-/
def Subrelation {α : Sort u} (q r : α → α → Prop) 
goal: Prop

full_name: InvImage
code: /--
The inverse image of `r : β → β → Prop` by a function `α → β` is the relation
`s : α → α → Prop` defined by `s a b = r (f a) (f b)`.
-/
def InvImage {α : Sort u} {β : Sort v} (r : β → β → Prop) (f : α → β) : α → α → Prop 
goal: α → α → Prop

full_name: TC
code: /--
The transitive closure `r⁺` of a relation `r` is the smallest relation which is
transitive and contains `r`. `r⁺ a z` if and only if there exists a sequence
`a r b r ... r z` of length at least 1 connecting `a` to `z`.
-/
inductive TC {α : Sort u} (r : α → α → Prop) : α → α → Prop where
  /-- If `r a b` then `r⁺ a b`. This is the base case of the transitive closure. -/
  | base  : ∀ a b, r a b → TC r a b
  /-- The transitive closure is transitive. -/
  | trans : ∀ a b c, TC r a b → TC r b c → TC r a c
goal: α → α → Prop

full_name: TC.base
code: /--
The transitive closure `r⁺` of a relation `r` is the smallest relation which is
transitive and contains `r`. `r⁺ a z` if and only if there exists a sequence
`a r b r ... r z` of length at least 1 connecting `a` to `z`.
-/
inductive TC {α : Sort u} (r : α → α → Prop) : α → α → Prop where
  /-- If `r a b` then `r⁺ a b`. This is the base case of the transitive closure. -/
  | base  : ∀ a b, r a b → TC r a b
  /-- The transitive closure is transitive. -/
  | trans : ∀ a b c, TC r a b → TC r b c → TC r a c
goal: r a b → TC r a b

full_name: TC.trans
code: /--
The transitive closure `r⁺` of a relation `r` is the smallest relation which is
transitive and contains `r`. `r⁺ a z` if and only if there exists a sequence
`a r b r ... r z` of length at least 1 connecting `a` to `z`.
-/
inductive TC {α : Sort u} (r : α → α → Prop) : α → α → Prop where
  /-- If `r a b` then `r⁺ a b`. This is the base case of the transitive closure. -/
  | base  : ∀ a b, r a b → TC r a b
  /-- The transitive closure is transitive. -/
  | trans : ∀ a b c, TC r a b → TC r b c → TC r a c
goal: TC r a b → TC r b c → TC r a c

full_name: Subtype.existsOfSubtype
code: theorem existsOfSubtype {α : Type u} {p : α → Prop} : { x // p x } → Exists (fun x => p x)
  
goal: (Subtype fun x => p x) → Exists fun x => p x

full_name: Subtype.eq
code: protected theorem eq : ∀ {a1 a2 : {x // p x}}, val a1 = val a2 → a1 = a2
  
goal: a1.val = a2.val → a1 = a2

full_name: Subtype.eta
code: theorem eta (a : {x // p x}) (h : p (val a)) : mk (val a) h = a 
goal: ⟨a.val, h⟩ = a

full_name: Subtype.«instDecidableEq_.lake»
code: instance {α : Type u} {p : α → Prop} [DecidableEq α] : DecidableEq {x : α // p x} 
goal: DecidableEq (Subtype fun x => p x)

full_name: Sum.inhabitedLeft
code: instance Sum.inhabitedLeft [Inhabited α] : Inhabited (Sum α β) 
goal: Inhabited (α ⊕ β)

full_name: Sum.inhabitedRight
code: instance Sum.inhabitedRight [Inhabited β] : Inhabited (Sum α β) 
goal: Inhabited (α ⊕ β)

full_name: instDecidableEqSum
code: instance {α : Type u} {β : Type v} [DecidableEq α] [DecidableEq β] : DecidableEq (Sum α β) 
goal: DecidableEq (α ⊕ β)

full_name: «instInhabitedProd_.lake»
code: instance [Inhabited α] [Inhabited β] : Inhabited (α × β) 
goal: Inhabited (α × β)

full_name: «instInhabitedMProd_.lake»
code: instance [Inhabited α] [Inhabited β] : Inhabited (MProd α β) 
goal: Inhabited (MProd α β)

full_name: «instInhabitedPProd_.lake»
code: instance [Inhabited α] [Inhabited β] : Inhabited (PProd α β) 
goal: Inhabited (PProd α β)

full_name: «instDecidableEqProd_.lake»
code: instance [DecidableEq α] [DecidableEq β] : DecidableEq (α × β) 
goal: DecidableEq (α × β)

full_name: «instBEqProd_.lake»
code: instance [BEq α] [BEq β] : BEq (α × β) 
goal: BEq (α × β)

full_name: Prod.lexLt
code: /-- Lexicographical order for products -/
def Prod.lexLt [LT α] [LT β] (s : α × β) (t : α × β) : Prop 
goal: Prop

full_name: Prod.lexLtDec
code: instance Prod.lexLtDec
    [LT α] [LT β] [DecidableEq α]
    [(a b : α) → Decidable (a < b)] [(a b : β) → Decidable (a < b)]
    : (s t : α × β) → Decidable (Prod.lexLt s t) 
goal: Decidable (s.lexLt t)

full_name: Prod.lexLt_def
code: theorem Prod.lexLt_def [LT α] [LT β] (s t : α × β) : (Prod.lexLt s t) = (s.1 < t.1 ∨ (s.1 = t.1 ∧ s.2 < t.2)) 
goal: s.lexLt t = (s.fst < t.fst ∨ s.fst = t.fst ∧ s.snd < t.snd)

full_name: Prod.eta
code: theorem Prod.eta (p : α × β) : (p.1, p.2) = p 
goal: { fst := p.fst, snd := p.snd } = p

full_name: Prod.map
code: /--
`Prod.map f g : α₁ × β₁ → α₂ × β₂` maps across a pair
by applying `f` to the first component and `g` to the second.
-/
def Prod.map {α₁ : Type u₁} {α₂ : Type u₂} {β₁ : Type v₁} {β₂ : Type v₂}
    (f : α₁ → α₂) (g : β₁ → β₂) : α₁ × β₁ → α₂ × β₂
  
goal: α₁ × β₁ → α₂ × β₂

full_name: Prod.map_apply
code: @[simp] theorem Prod.map_apply (f : α → β) (g : γ → δ) (x) (y) :
    Prod.map f g (x, y) = (f x, g y) 
goal: Prod.map f g { fst := x, snd := y } = { fst := f x, snd := g y }

full_name: Prod.map_fst
code: @[simp] theorem Prod.map_fst (f : α → β) (g : γ → δ) (x) : (Prod.map f g x).1 = f x.1 
goal: (Prod.map f g x).fst = f x.fst

full_name: Prod.map_snd
code: @[simp] theorem Prod.map_snd (f : α → β) (g : γ → δ) (x) : (Prod.map f g x).2 = g x.2 
goal: (Prod.map f g x).snd = g x.snd

full_name: ex_of_PSigma
code: theorem ex_of_PSigma {α : Type u} {p : α → Prop} : (PSigma (fun x => p x)) → Exists (fun x => p x)
  

full_name: PSigma.eta
code: protected theorem PSigma.eta {α : Sort u} {β : α → Sort v} {a₁ a₂ : α} {b₁ : β a₁} {b₂ : β a₂}
    (h₁ : a₁ = a₂) (h₂ : Eq.ndrec b₁ h₁ = b₂) : PSigma.mk a₁ b₁ = PSigma.mk a₂ b₂ 
goal: ⟨a₁, b₁⟩ = ⟨a₂, b₂⟩

full_name: PUnit.subsingleton
code: theorem PUnit.subsingleton (a b : PUnit) : a = b 
goal: a = b

full_name: PUnit.eq_punit
code: theorem PUnit.eq_punit (a : PUnit) : a = ⟨⟩ 
goal: a = PUnit.unit

full_name: instSubsingletonPUnit
code: instance : Subsingleton PUnit 
goal: Subsingleton PUnit

full_name: «instInhabitedPUnit_.lake»
code: instance : Inhabited PUnit 
goal: Inhabited PUnit

full_name: «instDecidableEqPUnit_.lake»
code: instance : DecidableEq PUnit 
goal: DecidableEq PUnit

full_name: Setoid.iseqv
code: /--
A setoid is a type with a distinguished equivalence relation, denoted `≈`.
This is mainly used as input to the `Quotient` type constructor.
-/
class Setoid (α : Sort u) where
  /-- `x ≈ y` is the distinguished equivalence relation of a setoid. -/
  r : α → α → Prop
  /-- The relation `x ≈ y` is an equivalence relation. -/
  iseqv : Equivalence r
goal: Equivalence Setoid.r

full_name: Setoid
code: /--
A setoid is a type with a distinguished equivalence relation, denoted `≈`.
This is mainly used as input to the `Quotient` type constructor.
-/
class Setoid (α : Sort u) where
  /-- `x ≈ y` is the distinguished equivalence relation of a setoid. -/
  r : α → α → Prop
  /-- The relation `x ≈ y` is an equivalence relation. -/
  iseqv : Equivalence r
goal: Sort (max 1 u)

full_name: Setoid.r
code: /--
A setoid is a type with a distinguished equivalence relation, denoted `≈`.
This is mainly used as input to the `Quotient` type constructor.
-/
class Setoid (α : Sort u) where
  /-- `x ≈ y` is the distinguished equivalence relation of a setoid. -/
  r : α → α → Prop
  /-- The relation `x ≈ y` is an equivalence relation. -/
  iseqv : Equivalence r
goal: α → α → Prop

full_name: instHasEquivOfSetoid
code: instance {α : Sort u} [Setoid α] : HasEquiv α 
goal: HasEquiv α

full_name: Setoid.refl
code: theorem refl (a : α) : a ≈ a 
goal: a ≈ a

full_name: Setoid.symm
code: theorem symm {a b : α} (hab : a ≈ b) : b ≈ a 
goal: b ≈ a

full_name: Setoid.trans
code: theorem trans {a b c : α} (hab : a ≈ b) (hbc : b ≈ c) : a ≈ c 
goal: a ≈ c

full_name: propext
code: /--
The axiom of **propositional extensionality**. It asserts that if propositions
`a` and `b` are logically equivalent (i.e. we can prove `a` from `b` and vice versa),
then `a` and `b` are *equal*, meaning that we can replace `a` with `b` in all
contexts.

For simple expressions like `a ∧ c ∨ d → e` we can prove that because all the logical
connectives respect logical equivalence, we can replace `a` with `b` in this expression
without using `propext`. However, for higher order expressions like `P a` where
`P : Prop → Prop` is unknown, or indeed for `a = b` itself, we cannot replace `a` with `b`
without an axiom which says exactly this.

This is a relatively uncontroversial axiom, which is intuitionistically valid.
It does however block computation when using `#reduce` to reduce proofs directly
(which is not recommended), meaning that canonicity,
the property that all closed terms of type `Nat` normalize to numerals,
fails to hold when this (or any) axiom is used:
```
set_option pp.proofs true

def foo : Nat := by
  have : (True → True) ↔ True := ⟨λ _ => trivial, λ _ _ => trivial⟩
  have := propext this ▸ (2 : Nat)
  exact this

#reduce foo
-- propext { mp := fun x x => True.intro, mpr := fun x => True.intro } ▸ 2

#eval foo -- 2
```
`#eval` can evaluate it to a numeral because the compiler erases casts and
does not evaluate proofs, so `propext`, whose return type is a proposition,
can never block it.
-/
axiom propext {a b : Prop} : (a ↔ b) → a = b
goal: (a ↔ b) → a = b

full_name: Eq.propIntro
code: theorem Eq.propIntro {a b : Prop} (h₁ : a → b) (h₂ : b → a) : a = b 
goal: a = b

full_name: instDecidableEqOfIff
code: instance {p q : Prop} [d : Decidable (p ↔ q)] : Decidable (p = q) 
goal: Decidable (p = q)

full_name: Nat.succ.inj
code: theorem Nat.succ.inj {m n : Nat} : m.succ = n.succ → m = n 
goal: m.succ = n.succ → m = n

full_name: Nat.succ.injEq
code: theorem Nat.succ.injEq (u v : Nat) : (u.succ = v.succ) = (u = v) 
goal: (u.succ = v.succ) = (u = v)

full_name: beq_iff_eq
code: @[simp] theorem beq_iff_eq [BEq α] [LawfulBEq α] (a b : α) : a == b ↔ a = b 
goal: (a == b) = true ↔ a = b

full_name: Not.elim
code: /-- *Ex falso* for negation: from `¬a` and `a` anything follows. This is the same as `absurd` with
the arguments flipped, but it is in the `Not` namespace so that projection notation can be used. -/
def Not.elim {α : Sort _} (H1 : ¬a) (H2 : a) : α 
goal: α

full_name: And.elim
code: /-- Non-dependent eliminator for `And`. -/
abbrev And.elim (f : a → b → α) (h : a ∧ b) : α 
goal: α

full_name: Iff.elim
code: /-- Non-dependent eliminator for `Iff`. -/
def Iff.elim (f : (a → b) → (b → a) → α) (h : a ↔ b) : α 
goal: α

full_name: Iff.subst
code: /-- Iff can now be used to do substitutions in a calculation -/
theorem Iff.subst {a b : Prop} {p : Prop → Prop} (h₁ : a ↔ b) (h₂ : p a) : p b 
goal: p b

full_name: Not.intro
code: theorem Not.intro {a : Prop} (h : a → False) : ¬a 
goal: ¬a

full_name: Not.imp
code: theorem Not.imp {a b : Prop} (H2 : ¬b) (H1 : a → b) : ¬a 
goal: ¬a

full_name: not_congr
code: theorem not_congr (h : a ↔ b) : ¬a ↔ ¬b 
goal: ¬a ↔ ¬b

full_name: not_not_not
code: theorem not_not_not : ¬¬¬a ↔ ¬a 
goal: ¬¬¬a ↔ ¬a

full_name: iff_of_true
code: theorem iff_of_true (ha : a) (hb : b) : a ↔ b 
goal: a ↔ b

full_name: iff_of_false
code: theorem iff_of_false (ha : ¬a) (hb : ¬b) : a ↔ b 
goal: a ↔ b

full_name: iff_true_left
code: theorem iff_true_left  (ha : a) : (a ↔ b) ↔ b 
goal: (a ↔ b) ↔ b

full_name: iff_true_right
code: theorem iff_true_right (ha : a) : (b ↔ a) ↔ b 
goal: (b ↔ a) ↔ b

full_name: iff_false_left
code: theorem iff_false_left  (ha : ¬a) : (a ↔ b) ↔ ¬b 
goal: (a ↔ b) ↔ ¬b

full_name: iff_false_right
code: theorem iff_false_right (ha : ¬a) : (b ↔ a) ↔ ¬b 
goal: (b ↔ a) ↔ ¬b

full_name: of_iff_true
code: theorem of_iff_true    (h : a ↔ True) : a 
goal: a

full_name: iff_true_intro
code: theorem iff_true_intro (h : a) : a ↔ True 
goal: a ↔ True

full_name: not_of_iff_false
code: theorem not_of_iff_false : (p ↔ False) → ¬p 
goal: (p ↔ False) → ¬p

full_name: iff_false_intro
code: theorem iff_false_intro (h : ¬a) : a ↔ False 
goal: a ↔ False

full_name: not_iff_false_intro
code: theorem not_iff_false_intro (h : a) : ¬a ↔ False 
goal: ¬a ↔ False

full_name: not_true
code: theorem not_true : (¬True) ↔ False 
goal: ¬True ↔ False

full_name: not_false_iff
code: theorem not_false_iff : (¬False) ↔ True 
goal: ¬False ↔ True

full_name: Eq.to_iff
code: theorem Eq.to_iff : a = b → (a ↔ b) 
goal: a = b → (a ↔ b)

full_name: iff_of_eq
code: theorem iff_of_eq : a = b → (a ↔ b) 
goal: a = b → (a ↔ b)

full_name: neq_of_not_iff
code: theorem neq_of_not_iff : ¬(a ↔ b) → a ≠ b 
goal: ¬(a ↔ b) → a ≠ b

full_name: iff_iff_eq
code: theorem iff_iff_eq : (a ↔ b) ↔ a = b 
goal: (a ↔ b) ↔ a = b

full_name: eq_iff_iff
code: @[simp] theorem eq_iff_iff : (a = b) ↔ (a ↔ b) 
goal: a = b ↔ (a ↔ b)

full_name: eq_self_iff_true
code: theorem eq_self_iff_true (a : α)  : a = a ↔ True  
goal: a = a ↔ True

full_name: ne_self_iff_false
code: theorem ne_self_iff_false (a : α) : a ≠ a ↔ False 
goal: a ≠ a ↔ False

full_name: false_of_true_iff_false
code: theorem false_of_true_iff_false (h : True ↔ False) : False 
goal: False

full_name: false_of_true_eq_false
code: theorem false_of_true_eq_false  (h : True = False) : False 
goal: False

full_name: true_eq_false_of_false
code: theorem true_eq_false_of_false : False → (True = False) 
goal: False → True = False

full_name: iff_def
code: theorem iff_def  : (a ↔ b) ↔ (a → b) ∧ (b → a) 
goal: (a ↔ b) ↔ (a → b) ∧ (b → a)

full_name: iff_def'
code: theorem iff_def' : (a ↔ b) ↔ (b → a) ∧ (a → b) 
goal: (a ↔ b) ↔ (b → a) ∧ (a → b)

full_name: true_iff_false
code: theorem true_iff_false : (True ↔ False) ↔ False 
goal: (True ↔ False) ↔ False

full_name: false_iff_true
code: theorem false_iff_true : (False ↔ True) ↔ False 
goal: (False ↔ True) ↔ False

full_name: iff_not_self
code: theorem iff_not_self : ¬(a ↔ ¬a) 
goal: ¬(a ↔ ¬a)

full_name: heq_self_iff_true
code: theorem heq_self_iff_true (a : α) : HEq a a ↔ True 
goal: HEq a a ↔ True

full_name: not_not_of_not_imp
code: theorem not_not_of_not_imp : ¬(a → b) → ¬¬a 
goal: ¬(a → b) → ¬¬a

full_name: not_of_not_imp
code: theorem not_of_not_imp {a : Prop} : ¬(a → b) → ¬b 
goal: ¬(a → b) → ¬b

full_name: imp_not_self
code: @[simp] theorem imp_not_self : (a → ¬a) ↔ ¬a 
goal: a → ¬a ↔ ¬a

full_name: imp_intro
code: theorem imp_intro {α β : Prop} (h : α) : β → α 
goal: β → α

full_name: imp_imp_imp
code: theorem imp_imp_imp {a b c d : Prop} (h₀ : c → a) (h₁ : b → d) : (a → b) → (c → d) 
goal: (a → b) → c → d

full_name: imp_iff_right
code: theorem imp_iff_right {a : Prop} (ha : a) : (a → b) ↔ b 
goal: a → b ↔ b

full_name: imp_true_iff
code: theorem imp_true_iff (α : Sort u) : (α → True) ↔ True 
goal: α → True ↔ True

full_name: false_imp_iff
code: theorem false_imp_iff (a : Prop) : (False → a) ↔ True 
goal: False → a ↔ True

full_name: true_imp_iff
code: theorem true_imp_iff (α : Prop) : (True → α) ↔ α 
goal: True → α ↔ α

full_name: imp_self
code: @[simp high] theorem imp_self : (a → a) ↔ True 
goal: a → a ↔ True

full_name: imp_false
code: @[simp] theorem imp_false : (a → False) ↔ ¬a 
goal: a → False ↔ ¬a

full_name: imp.swap
code: theorem imp.swap : (a → b → c) ↔ (b → a → c) 
goal: a → b → c ↔ b → a → c

full_name: imp_not_comm
code: theorem imp_not_comm : (a → ¬b) ↔ (b → ¬a) 
goal: a → ¬b ↔ b → ¬a

full_name: imp_congr_left
code: theorem imp_congr_left (h : a ↔ b) : (a → c) ↔ (b → c) 
goal: a → c ↔ b → c

full_name: imp_congr_right
code: theorem imp_congr_right (h : a → (b ↔ c)) : (a → b) ↔ (a → c) 
goal: a → b ↔ a → c

full_name: imp_congr_ctx
code: theorem imp_congr_ctx (h₁ : a ↔ c) (h₂ : c → (b ↔ d)) : (a → b) ↔ (c → d) 
goal: a → b ↔ c → d

full_name: imp_congr
code: theorem imp_congr (h₁ : a ↔ c) (h₂ : b ↔ d) : (a → b) ↔ (c → d) 
goal: a → b ↔ c → d

full_name: imp_iff_not
code: theorem imp_iff_not (hb : ¬b) : a → b ↔ ¬a 
goal: a → b ↔ ¬a

full_name: Quot.sound
code: /--
The **quotient axiom**, or at least the nontrivial part of the quotient
axiomatization. Quotient types are introduced by the `init_quot` command
in `Init.Prelude` which introduces the axioms:

```
opaque Quot {α : Sort u} (r : α → α → Prop) : Sort u

opaque Quot.mk {α : Sort u} (r : α → α → Prop) (a : α) : Quot r

opaque Quot.lift {α : Sort u} {r : α → α → Prop} {β : Sort v} (f : α → β) :
  (∀ a b : α, r a b → f a = f b) → Quot r → β

opaque Quot.ind {α : Sort u} {r : α → α → Prop} {β : Quot r → Prop} :
  (∀ a : α, β (Quot.mk r a)) → ∀ q : Quot r, β q
```
All of these axioms are true if we assume `Quot α r = α` and `Quot.mk` and
`Quot.lift` are identity functions, so they do not add much. However this axiom
cannot be explained in that way (it is false for that interpretation), so the
real power of quotient types come from this axiom.

It says that the quotient by `r` maps elements which are related by `r` to equal
values in the quotient. Together with `Quot.lift` which says that functions
which respect `r` can be lifted to functions on the quotient, we can deduce that
`Quot α r` exactly consists of the equivalence classes with respect to `r`.

It is important to note that `r` need not be an equivalence relation in this axiom.
When `r` is not an equivalence relation, we are actually taking a quotient with
respect to the equivalence relation generated by `r`.
-/
axiom sound : ∀ {α : Sort u} {r : α → α → Prop} {a b : α}, r a b → Quot.mk r a = Quot.mk r b
goal: r a b → Quot.mk r a = Quot.mk r b

full_name: Quot.liftBeta
code: protected theorem liftBeta {α : Sort u} {r : α → α → Prop} {β : Sort v}
    (f : α → β)
    (c : (a b : α) → r a b → f a = f b)
    (a : α)
    : lift f c (Quot.mk r a) = f a 
goal: Quot.lift f c (Quot.mk r a) = f a

full_name: Quot.indBeta
code: protected theorem indBeta {α : Sort u} {r : α → α → Prop} {motive : Quot r → Prop}
    (p : (a : α) → motive (Quot.mk r a))
    (a : α)
    : (ind p (Quot.mk r a) : motive (Quot.mk r a)) = p a 
goal: ⋯ = ⋯

full_name: Quot.liftOn
code: /--
`Quot.liftOn q f h` is the same as `Quot.lift f h q`. It just reorders
the argument `q : Quot r` to be first.
-/
protected abbrev liftOn {α : Sort u} {β : Sort v} {r : α → α → Prop}
  (q : Quot r) (f : α → β) (c : (a b : α) → r a b → f a = f b) : β 
goal: β

full_name: Quot.inductionOn
code: @[elab_as_elim]
protected theorem inductionOn {α : Sort u} {r : α → α → Prop} {motive : Quot r → Prop}
    (q : Quot r)
    (h : (a : α) → motive (Quot.mk r a))
    : motive q 
goal: motive q

full_name: Quot.exists_rep
code: theorem exists_rep {α : Sort u} {r : α → α → Prop} (q : Quot r) : Exists (fun a => (Quot.mk r a) = q) 
goal: Exists fun a => Quot.mk r a = q

full_name: Quot.indep
code: /-- Auxiliary definition for `Quot.rec`. -/
@[reducible, macro_inline]
protected def indep (f : (a : α) → motive (Quot.mk r a)) (a : α) : PSigma motive 
goal: PSigma motive

full_name: Quot.indepCoherent
code: protected theorem indepCoherent
    (f : (a : α) → motive (Quot.mk r a))
    (h : (a b : α) → (p : r a b) → Eq.ndrec (f a) (sound p) = f b)
    : (a b : α) → r a b → Quot.indep f a = Quot.indep f b  
goal: r a b → Quot.indep f a = Quot.indep f b

full_name: Quot.liftIndepPr1
code: protected theorem liftIndepPr1
    (f : (a : α) → motive (Quot.mk r a))
    (h : ∀ (a b : α) (p : r a b), Eq.ndrec (f a) (sound p) = f b)
    (q : Quot r)
    : (lift (Quot.indep f) (Quot.indepCoherent f h) q).1 = q 
goal: (Quot.lift (Quot.indep f) ⋯ q).fst = q

full_name: Quot.rec
code: /--
Dependent recursion principle for `Quot`. This constructor can be tricky to use,
so you should consider the simpler versions if they apply:
* `Quot.lift`, for nondependent functions
* `Quot.ind`, for theorems / proofs of propositions about quotients
* `Quot.recOnSubsingleton`, when the target type is a `Subsingleton`
* `Quot.hrecOn`, which uses `HEq (f a) (f b)` instead of a `sound p ▸ f a = f b` assummption
-/
protected abbrev rec
    (f : (a : α) → motive (Quot.mk r a))
    (h : (a b : α) → (p : r a b) → Eq.ndrec (f a) (sound p) = f b)
    (q : Quot r) : motive q 
goal: motive q

full_name: Quot.recOn
code: @[inherit_doc Quot.rec] protected abbrev recOn
    (q : Quot r)
    (f : (a : α) → motive (Quot.mk r a))
    (h : (a b : α) → (p : r a b) → Eq.ndrec (f a) (sound p) = f b)
    : motive q 
goal: motive q

full_name: Quot.recOnSubsingleton
code: /--
Dependent induction principle for a quotient, when the target type is a `Subsingleton`.
In this case the quotient's side condition is trivial so any function can be lifted.
-/
protected abbrev recOnSubsingleton
    [h : (a : α) → Subsingleton (motive (Quot.mk r a))]
    (q : Quot r)
    (f : (a : α) → motive (Quot.mk r a))
    : motive q 
goal: motive q

full_name: Quot.hrecOn
code: /--
Heterogeneous dependent recursion principle for a quotient.
This may be easier to work with since it uses `HEq` instead of
an `Eq.ndrec` in the hypothesis.
-/
protected abbrev hrecOn
    (q : Quot r)
    (f : (a : α) → motive (Quot.mk r a))
    (c : (a b : α) → (p : r a b) → HEq (f a) (f b))
    : motive q 
goal: motive q

full_name: Quotient
code: /--
`Quotient α s` is the same as `Quot α r`, but it is specialized to a setoid `s`
(that is, an equivalence relation) instead of an arbitrary relation.
Prefer `Quotient` over `Quot` if your relation is actually an equivalence relation.
-/
def Quotient {α : Sort u} (s : Setoid α) 
goal: Sort u

full_name: Quotient.mk
code: /-- The canonical quotient map into a `Quotient`. -/
@[inline]
protected def mk {α : Sort u} (s : Setoid α) (a : α) : Quotient s 
goal: Quotient s

full_name: Quotient.mk'
code: /--
The canonical quotient map into a `Quotient`.
(This synthesizes the setoid by typeclass inference.)
-/
protected def mk' {α : Sort u} [s : Setoid α] (a : α) : Quotient s 
goal: Quotient s

full_name: Quotient.sound
code: /--
The analogue of `Quot.sound`: If `a` and `b` are related by the equivalence relation,
then they have equal equivalence classes.
-/
theorem sound {α : Sort u} {s : Setoid α} {a b : α} : a ≈ b → Quotient.mk s a = Quotient.mk s b 
goal: a ≈ b → Quotient.mk s a = Quotient.mk s b

full_name: Quotient.lift
code: /--
The analogue of `Quot.lift`: if `f : α → β` respects the equivalence relation `≈`,
then it lifts to a function on `Quotient s` such that `lift f h (mk a) = f a`.
-/
protected abbrev lift {α : Sort u} {β : Sort v} {s : Setoid α} (f : α → β) : ((a b : α) → a ≈ b → f a = f b) → Quotient s → β 
goal: (∀ (a b : α), a ≈ b → f a = f b) → Quotient s → β

full_name: Quotient.ind
code: /-- The analogue of `Quot.ind`: every element of `Quotient s` is of the form `Quotient.mk s a`. -/
protected theorem ind {α : Sort u} {s : Setoid α} {motive : Quotient s → Prop} : ((a : α) → motive (Quotient.mk s a)) → (q : Quotient s) → motive q 
goal: (∀ (a : α), motive (Quotient.mk s a)) → ∀ (q : Quotient s), motive q

full_name: Quotient.liftOn
code: /--
The analogue of `Quot.liftOn`: if `f : α → β` respects the equivalence relation `≈`,
then it lifts to a function on `Quotient s` such that `lift (mk a) f h = f a`.
-/
protected abbrev liftOn {α : Sort u} {β : Sort v} {s : Setoid α} (q : Quotient s) (f : α → β) (c : (a b : α) → a ≈ b → f a = f b) : β 
goal: β

full_name: Quotient.inductionOn
code: /-- The analogue of `Quot.inductionOn`: every element of `Quotient s` is of the form `Quotient.mk s a`. -/
@[elab_as_elim]
protected theorem inductionOn {α : Sort u} {s : Setoid α} {motive : Quotient s → Prop}
    (q : Quotient s)
    (h : (a : α) → motive (Quotient.mk s a))
    : motive q 
goal: motive q

full_name: Quotient.exists_rep
code: theorem exists_rep {α : Sort u} {s : Setoid α} (q : Quotient s) : Exists (fun (a : α) => Quotient.mk s a = q) 
goal: Exists fun a => Quotient.mk s a = q

full_name: Quotient.rec
code: /-- The analogue of `Quot.rec` for `Quotient`. See `Quot.rec`. -/
@[inline, elab_as_elim]
protected def rec
    (f : (a : α) → motive (Quotient.mk s a))
    (h : (a b : α) → (p : a ≈ b) → Eq.ndrec (f a) (Quotient.sound p) = f b)
    (q : Quotient s)
    : motive q 
goal: motive q

full_name: Quotient.recOn
code: /-- The analogue of `Quot.recOn` for `Quotient`. See `Quot.recOn`. -/
@[elab_as_elim]
protected abbrev recOn
    (q : Quotient s)
    (f : (a : α) → motive (Quotient.mk s a))
    (h : (a b : α) → (p : a ≈ b) → Eq.ndrec (f a) (Quotient.sound p) = f b)
    : motive q 
goal: motive q

full_name: Quotient.recOnSubsingleton
code: /-- The analogue of `Quot.recOnSubsingleton` for `Quotient`. See `Quot.recOnSubsingleton`. -/
@[elab_as_elim]
protected abbrev recOnSubsingleton
    [h : (a : α) → Subsingleton (motive (Quotient.mk s a))]
    (q : Quotient s)
    (f : (a : α) → motive (Quotient.mk s a))
    : motive q 
goal: motive q

full_name: Quotient.hrecOn
code: /-- The analogue of `Quot.hrecOn` for `Quotient`. See `Quot.hrecOn`. -/
@[elab_as_elim]
protected abbrev hrecOn
    (q : Quotient s)
    (f : (a : α) → motive (Quotient.mk s a))
    (c : (a b : α) → (p : a ≈ b) → HEq (f a) (f b))
    : motive q 
goal: motive q

full_name: Quotient.lift₂
code: /-- Lift a binary function to a quotient on both arguments. -/
protected abbrev lift₂
    (f : α → β → φ)
    (c : (a₁ : α) → (b₁ : β) → (a₂ : α) → (b₂ : β) → a₁ ≈ a₂ → b₁ ≈ b₂ → f a₁ b₁ = f a₂ b₂)
    (q₁ : Quotient s₁) (q₂ : Quotient s₂)
    : φ 
goal: φ

full_name: Quotient.liftOn₂
code: /-- Lift a binary function to a quotient on both arguments. -/
protected abbrev liftOn₂
    (q₁ : Quotient s₁)
    (q₂ : Quotient s₂)
    (f : α → β → φ)
    (c : (a₁ : α) → (b₁ : β) → (a₂ : α) → (b₂ : β) → a₁ ≈ a₂ → b₁ ≈ b₂ → f a₁ b₁ = f a₂ b₂)
    : φ 
goal: φ

full_name: Quotient.ind₂
code: @[elab_as_elim]
protected theorem ind₂
    {motive : Quotient s₁ → Quotient s₂ → Prop}
    (h : (a : α) → (b : β) → motive (Quotient.mk s₁ a) (Quotient.mk s₂ b))
    (q₁ : Quotient s₁)
    (q₂ : Quotient s₂)
    : motive q₁ q₂ 
goal: motive q₁ q₂

full_name: Quotient.inductionOn₂
code: @[elab_as_elim]
protected theorem inductionOn₂
    {motive : Quotient s₁ → Quotient s₂ → Prop}
    (q₁ : Quotient s₁)
    (q₂ : Quotient s₂)
    (h : (a : α) → (b : β) → motive (Quotient.mk s₁ a) (Quotient.mk s₂ b))
    : motive q₁ q₂ 
goal: motive q₁ q₂

full_name: Quotient.inductionOn₃
code: @[elab_as_elim]
protected theorem inductionOn₃
    {s₃ : Setoid φ}
    {motive : Quotient s₁ → Quotient s₂ → Quotient s₃ → Prop}
    (q₁ : Quotient s₁)
    (q₂ : Quotient s₂)
    (q₃ : Quotient s₃)
    (h : (a : α) → (b : β) → (c : φ) → motive (Quotient.mk s₁ a) (Quotient.mk s₂ b) (Quotient.mk s₃ c))
    : motive q₁ q₂ q₃ 
goal: motive q₁ q₂ q₃

full_name: _private.«.lake».packages.lean4.src.lean.Init.Core.0.Quotient.rel
code: private def rel {s : Setoid α} (q₁ q₂ : Quotient s) : Prop 
goal: Prop

full_name: _private.«.lake».packages.lean4.src.lean.Init.Core.0.Quotient.rel.refl
code: private theorem rel.refl {s : Setoid α} (q : Quotient s) : rel q q 
goal: Quotient.rel q q

full_name: _private.«.lake».packages.lean4.src.lean.Init.Core.0.Quotient.rel_of_eq
code: private theorem rel_of_eq {s : Setoid α} {q₁ q₂ : Quotient s} : q₁ = q₂ → rel q₁ q₂ 
goal: q₁ = q₂ → Quotient.rel q₁ q₂

full_name: Quotient.exact
code: theorem exact {s : Setoid α} {a b : α} : Quotient.mk s a = Quotient.mk s b → a ≈ b 
goal: Quotient.mk s a = Quotient.mk s b → a ≈ b

full_name: Quotient.recOnSubsingleton₂
code: /-- Lift a binary function to a quotient on both arguments. -/
@[elab_as_elim]
protected abbrev recOnSubsingleton₂
    {motive : Quotient s₁ → Quotient s₂ → Sort uC}
    [s : (a : α) → (b : β) → Subsingleton (motive (Quotient.mk s₁ a) (Quotient.mk s₂ b))]
    (q₁ : Quotient s₁)
    (q₂ : Quotient s₂)
    (g : (a : α) → (b : β) → motive (Quotient.mk s₁ a) (Quotient.mk s₂ b))
    : motive q₁ q₂ 
goal: motive q₁ q₂

full_name: instDecidableEqQuotientOfDecidableEquiv
code: instance {α : Sort u} {s : Setoid α} [d : ∀ (a b : α), Decidable (a ≈ b)] : DecidableEq (Quotient s) 
goal: DecidableEq (Quotient s)

full_name: funext
code: /--
**Function extensionality** is the statement that if two functions take equal values
every point, then the functions themselves are equal: `(∀ x, f x = g x) → f = g`.
It is called "extensionality" because it talks about how to prove two objects are equal
based on the properties of the object (compare with set extensionality,
which is `(∀ x, x ∈ s ↔ x ∈ t) → s = t`).

This is often an axiom in dependent type theory systems, because it cannot be proved
from the core logic alone. However in lean's type theory this follows from the existence
of quotient types (note the `Quot.sound` in the proof, as well as the `show` line
which makes use of the definitional equality `Quot.lift f h (Quot.mk x) = f x`).
-/
theorem funext {α : Sort u} {β : α → Sort v} {f g : (x : α) → β x}
    (h : ∀ x, f x = g x) : f = g 
goal: f = g

full_name: instSubsingletonForall
code: instance {α : Sort u} {β : α → Sort v} [∀ a, Subsingleton (β a)] : Subsingleton (∀ a, β a) 
goal: Subsingleton ((a : α) → β a)

full_name: Squash
code: /--
`Squash α` is the quotient of `α` by the always true relation.
It is empty if `α` is empty, otherwise it is a singleton.
(Thus it is unconditionally a `Subsingleton`.)
It is the "universal `Subsingleton`" mapped from `α`.

It is similar to `Nonempty α`, which has the same properties, but unlike
`Nonempty` this is a `Type u`, that is, it is "data", and the compiler
represents an element of `Squash α` the same as `α` itself
(as compared to `Nonempty α`, whose elements are represented by a dummy value).

`Squash.lift` will extract a value in any subsingleton `β` from a function on `α`,
while `Nonempty.rec` can only do the same when `β` is a proposition.
-/
def Squash (α : Type u) 
goal: Type u

full_name: Squash.mk
code: /-- The canonical quotient map into `Squash α`. -/
def Squash.mk {α : Type u} (x : α) : Squash α 
goal: Squash α

full_name: Squash.ind
code: theorem Squash.ind {α : Type u} {motive : Squash α → Prop} (h : ∀ (a : α), motive (Squash.mk a)) : ∀ (q : Squash α), motive q 
goal: motive q

full_name: Squash.lift
code: /-- If `β` is a subsingleton, then a function `α → β` lifts to `Squash α → β`. -/
@[inline] def Squash.lift {α β} [Subsingleton β] (s : Squash α) (f : α → β) : β 
goal: β

full_name: instSubsingletonSquash
code: instance : Subsingleton (Squash α) 
goal: Subsingleton (Squash α)

full_name: Antisymm
code: /--
`Antisymm (·≤·)` says that `(·≤·)` is antisymmetric, that is, `a ≤ b → b ≤ a → a = b`.
-/
class Antisymm {α : Sort u} (r : α → α → Prop) where
  /-- An antisymmetric relation `(·≤·)` satisfies `a ≤ b → b ≤ a → a = b`. -/
  antisymm {a b : α} : r a b → r b a → a = b
goal: Type

full_name: Antisymm.antisymm
code: /--
`Antisymm (·≤·)` says that `(·≤·)` is antisymmetric, that is, `a ≤ b → b ≤ a → a = b`.
-/
class Antisymm {α : Sort u} (r : α → α → Prop) where
  /-- An antisymmetric relation `(·≤·)` satisfies `a ≤ b → b ≤ a → a = b`. -/
  antisymm {a b : α} : r a b → r b a → a = b
goal: r a b → r b a → a = b

full_name: Lean.trustCompiler
code: /--
Depends on the correctness of the Lean compiler, interpreter, and all `[implemented_by ...]` and `[extern ...]` annotations.
-/
axiom trustCompiler : True
goal: True

full_name: Lean.reduceBool
code: /--
When the kernel tries to reduce a term `Lean.reduceBool c`, it will invoke the Lean interpreter to evaluate `c`.
The kernel will not use the interpreter if `c` is not a constant.
This feature is useful for performing proofs by reflection.

Remark: the Lean frontend allows terms of the from `Lean.reduceBool t` where `t` is a term not containing
free variables. The frontend automatically declares a fresh auxiliary constant `c` and replaces the term with
`Lean.reduceBool c`. The main motivation is that the code for `t` will be pre-compiled.

Warning: by using this feature, the Lean compiler and interpreter become part of your trusted code base.
This is extra 30k lines of code. More importantly, you will probably not be able to check your development using
external type checkers (e.g., Trepplein) that do not implement this feature.
Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter.
So, you are mainly losing the capability of type checking your development using external checkers.

Recall that the compiler trusts the correctness of all `[implemented_by ...]` and `[extern ...]` annotations.
If an extern function is executed, then the trusted code base will also include the implementation of the associated
foreign function.
-/
opaque reduceBool (b : Bool) : Bool 
goal: Bool

full_name: Lean.reduceNat
code: /--
Similar to `Lean.reduceBool` for closed `Nat` terms.

Remark: we do not have plans for supporting a generic `reduceValue {α} (a : α) : α := a`.
The main issue is that it is non-trivial to convert an arbitrary runtime object back into a Lean expression.
We believe `Lean.reduceBool` enables most interesting applications (e.g., proof by reflection).
-/
opaque reduceNat (n : Nat) : Nat 
goal: Nat

full_name: Lean.ofReduceBool
code: /--
The axiom `ofReduceBool` is used to perform proofs by reflection. See `reduceBool`.

This axiom is usually not used directly, because it has some syntactic restrictions.
Instead, the `native_decide` tactic can be used to prove any proposition whose
decidability instance can be evaluated to `true` using the lean compiler / interpreter.

Warning: by using this feature, the Lean compiler and interpreter become part of your trusted code base.
This is extra 30k lines of code. More importantly, you will probably not be able to check your development using
external type checkers (e.g., Trepplein) that do not implement this feature.
Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter.
So, you are mainly losing the capability of type checking your development using external checkers.
-/
axiom ofReduceBool (a b : Bool) (h : reduceBool a = b) : a = b
goal: a = b

full_name: Lean.ofReduceNat
code: /--
The axiom `ofReduceNat` is used to perform proofs by reflection. See `reduceBool`.

Warning: by using this feature, the Lean compiler and interpreter become part of your trusted code base.
This is extra 30k lines of code. More importantly, you will probably not be able to check your development using
external type checkers (e.g., Trepplein) that do not implement this feature.
Keep in mind that if you are using Lean as programming language, you are already trusting the Lean compiler and interpreter.
So, you are mainly losing the capability of type checking your development using external checkers.
-/
axiom ofReduceNat (a b : Nat) (h : reduceNat a = b) : a = b
goal: a = b

full_name: ge_iff_le
code: @[simp] theorem ge_iff_le [LE α] {x y : α} : x ≥ y ↔ y ≤ x 
goal: x ≥ y ↔ y ≤ x

full_name: gt_iff_lt
code: @[simp] theorem gt_iff_lt [LT α] {x y : α} : x > y ↔ y < x 
goal: x > y ↔ y < x

full_name: le_of_eq_of_le
code: theorem le_of_eq_of_le {a b c : α} [LE α] (h₁ : a = b) (h₂ : b ≤ c) : a ≤ c 
goal: a ≤ c

full_name: le_of_le_of_eq
code: theorem le_of_le_of_eq {a b c : α} [LE α] (h₁ : a ≤ b) (h₂ : b = c) : a ≤ c 
goal: a ≤ c

full_name: lt_of_eq_of_lt
code: theorem lt_of_eq_of_lt {a b c : α} [LT α] (h₁ : a = b) (h₂ : b < c) : a < c 
goal: a < c

full_name: lt_of_lt_of_eq
code: theorem lt_of_lt_of_eq {a b c : α} [LT α] (h₁ : a < b) (h₂ : b = c) : a < c 
goal: a < c

full_name: Std.Associative.assoc
code: /--
`Associative op` indicates `op` is an associative operation,
i.e. `(a ∘ b) ∘ c = a ∘ (b ∘ c)`.
-/
class Associative (op : α → α → α) : Prop where
  /-- An associative operation satisfies `(a ∘ b) ∘ c = a ∘ (b ∘ c)`. -/
  assoc : (a b c : α) → op (op a b) c = op a (op b c)
goal: op (op a b) c = op a (op b c)

full_name: Std.Associative
code: /--
`Associative op` indicates `op` is an associative operation,
i.e. `(a ∘ b) ∘ c = a ∘ (b ∘ c)`.
-/
class Associative (op : α → α → α) : Prop where
  /-- An associative operation satisfies `(a ∘ b) ∘ c = a ∘ (b ∘ c)`. -/
  assoc : (a b c : α) → op (op a b) c = op a (op b c)
goal: Prop

full_name: Std.Commutative
code: /--
`Commutative op` says that `op` is a commutative operation,
i.e. `a ∘ b = b ∘ a`.
-/
class Commutative (op : α → α → α) : Prop where
  /-- A commutative operation satisfies `a ∘ b = b ∘ a`. -/
  comm : (a b : α) → op a b = op b a
goal: Prop

full_name: Std.Commutative.comm
code: /--
`Commutative op` says that `op` is a commutative operation,
i.e. `a ∘ b = b ∘ a`.
-/
class Commutative (op : α → α → α) : Prop where
  /-- A commutative operation satisfies `a ∘ b = b ∘ a`. -/
  comm : (a b : α) → op a b = op b a
goal: op a b = op b a

full_name: Std.IdempotentOp
code: /--
`IdempotentOp op` indicates `op` is an idempotent binary operation.
i.e. `a ∘ a = a`.
-/
class IdempotentOp (op : α → α → α) : Prop where
  /-- An idempotent operation satisfies `a ∘ a = a`. -/
  idempotent : (x : α) → op x x = x
goal: Prop

full_name: Std.IdempotentOp.idempotent
code: /--
`IdempotentOp op` indicates `op` is an idempotent binary operation.
i.e. `a ∘ a = a`.
-/
class IdempotentOp (op : α → α → α) : Prop where
  /-- An idempotent operation satisfies `a ∘ a = a`. -/
  idempotent : (x : α) → op x x = x
goal: op x x = x

full_name: Std.LeftIdentity
code: /--
`LeftIdentify op o` indicates `o` is a left identity of `op`.

This class does not require a proof that `o` is an identity, and
is used primarily for infering the identity using class resoluton.
-/
class LeftIdentity (op : α → β → β) (o : outParam α) : Prop
goal: Prop

full_name: Std.LawfulLeftIdentity
code: /--
`LawfulLeftIdentify op o` indicates `o` is a verified left identity of
`op`.
-/
class LawfulLeftIdentity (op : α → β → β) (o : outParam α) extends LeftIdentity op o : Prop where
  /-- Left identity `o` is an identity. -/
  left_id : ∀ a, op o a = a
goal: Prop

full_name: Std.LawfulLeftIdentity.left_id
code: /--
`LawfulLeftIdentify op o` indicates `o` is a verified left identity of
`op`.
-/
class LawfulLeftIdentity (op : α → β → β) (o : outParam α) extends LeftIdentity op o : Prop where
  /-- Left identity `o` is an identity. -/
  left_id : ∀ a, op o a = a
goal: op o a = a

full_name: Std.RightIdentity
code: /--
`RightIdentify op o` indicates `o` is a right identity `o` of `op`.

This class does not require a proof that `o` is an identity, and is used
primarily for infering the identity using class resoluton.
-/
class RightIdentity (op : α → β → α) (o : outParam β) : Prop
goal: Prop

full_name: Std.LawfulRightIdentity
code: /--
`LawfulRightIdentify op o` indicates `o` is a verified right identity of
`op`.
-/
class LawfulRightIdentity (op : α → β → α) (o : outParam β) extends RightIdentity op o : Prop where
  /-- Right identity `o` is an identity. -/
  right_id : ∀ a, op a o = a
goal: Prop

full_name: Std.LawfulRightIdentity.right_id
code: /--
`LawfulRightIdentify op o` indicates `o` is a verified right identity of
`op`.
-/
class LawfulRightIdentity (op : α → β → α) (o : outParam β) extends RightIdentity op o : Prop where
  /-- Right identity `o` is an identity. -/
  right_id : ∀ a, op a o = a
goal: op a o = a

full_name: Std.Identity
code: /--
`Identity op o` indicates `o` is a left and right identity of `op`.

This class does not require a proof that `o` is an identity, and is used
primarily for infering the identity using class resoluton.
-/
class Identity (op : α → α → α) (o : outParam α) extends LeftIdentity op o, RightIdentity op o : Prop
goal: Prop

full_name: Std.LawfulIdentity
code: /--
`LawfulIdentity op o` indicates `o` is a verified left and right
identity of `op`.
-/
class LawfulIdentity (op : α → α → α) (o : outParam α) extends Identity op o, LawfulLeftIdentity op o, LawfulRightIdentity op o : Prop
goal: Prop

full_name: Std.LawfulCommIdentity
code: /--
`LawfulCommIdentity` can simplify defining instances of `LawfulIdentity`
on commutative functions by requiring only a left or right identity
proof.

This class is intended for simplifying defining instances of
`LawfulIdentity` and functions needed commutative operations with
identity should just add a `LawfulIdentity` constraint.
-/
class LawfulCommIdentity (op : α → α → α) (o : outParam α) [hc : Commutative op] extends LawfulIdentity op o : Prop where
  left_id a := Eq.trans (hc.comm o a) (right_id a)
  right_id a := Eq.trans (hc.comm a o) (left_id a)
goal: Prop

full_name: Std.instCommutativeOr
code: instance : Commutative Or 
goal: Std.Commutative Or

full_name: Std.instCommutativeAnd
code: instance : Commutative And 
goal: Std.Commutative And

full_name: Std.instCommutativeIff
code: instance : Commutative Iff 
goal: Std.Commutative Iff