Lean 语言参考

19.4. 命题等价🔗

命题等价是允许将两个项的相等性表述为命题的运算符。 必要时会自动检查 定义等价。 因此,为了保持检查它的算法快速且易于理解,它的表达能力受到限制。 另一方面,命题等价 必须显式证明并显式使用 - Lean 检查证明的有效性,而不是确定陈述是否正确。 作为交换,它更具表现力:许多术语在命题上相等,但在定义上并不相等。

命题等价 定义为归纳类型。 它的唯一构造函数 Eq.refl 要求两个相等的值相同;这隐含地呼吁 定义等价。 命题等价 也可以被认为是模 定义等价 的最小自反关系。 除了 Eq.refl 之外,等式证明还由 propextQuot.sound 公理生成。

🔗inductive predicate
Eq.{u_1} {α : Sort u_1} : α α Prop
Eq.{u_1} {α : Sort u_1} : α α Prop

The equality relation. It has one introduction rule, Eq.refl. We use a = b as notation for Eq a b. A fundamental property of equality is that it is an equivalence relation.

variable (α : Type) (a b c d : α) variable (hab : a = b) (hcb : c = b) (hcd : c = d) example : a = d := Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd

Equality is much more than an equivalence relation, however. It has the important property that every assertion respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value. That is, given h1 : a = b and h2 : p a, we can construct a proof for p b using substitution: Eq.subst h1 h2. Example:

example (α : Type) (a b : α) (p : α Prop) (h1 : a = b) (h2 : p a) : p b := Eq.subst h1 h2 example (α : Type) (a b : α) (p : α Prop) (h1 : a = b) (h2 : p a) : p b := h1 h2

The triangle in the second presentation is a macro built on top of Eq.subst and Eq.symm, and you can enter it by typing \t. For more information: Equality

Conventions for notations in identifiers:

  • The recommended spelling of = in identifiers is eq.

Constructors

Eq.refl.{u_1} {α : Sort u_1} (a : α) : a = a

Eq.refl a : a = a is reflexivity, the unique constructor of the equality type. See also rfl, which is usually used instead.

syntaxPropositional Equality
term ::= ...
    | The equality relation. It has one introduction rule, `Eq.refl`.
We use `a = b` as notation for `Eq a b`.
A fundamental property of equality is that it is an equivalence relation.
```
variable (α : Type) (a b c d : α)
variable (hab : a = b) (hcb : c = b) (hcd : c = d)

example : a = d :=
  Eq.trans (Eq.trans hab (Eq.symm hcb)) hcd
```
Equality is much more than an equivalence relation, however. It has the important property that every assertion
respects the equivalence, in the sense that we can substitute equal expressions without changing the truth value.
That is, given `h1 : a = b` and `h2 : p a`, we can construct a proof for `p b` using substitution: `Eq.subst h1 h2`.
Example:
```
example (α : Type) (a b : α) (p : α → Prop)
        (h1 : a = b) (h2 : p a) : p b :=
  Eq.subst h1 h2

example (α : Type) (a b : α) (p : α → Prop)
    (h1 : a = b) (h2 : p a) : p b :=
  h1 ▸ h2
```
The triangle in the second presentation is a macro built on top of `Eq.subst` and `Eq.symm`, and you can enter it by typing `\t`.
For more information: [Equality](https://lean-lang.org/theorem_proving_in_lean4/quantifiers_and_equality.html#equality)


Conventions for notations in identifiers:

 * The recommended spelling of `=` in identifiers is `eq`.term = term

命题等价 通常由中缀 = 运算符表示。

🔗def
rfl.{u} {α : Sort u} {a : α} : a = a
rfl.{u} {α : Sort u} {a : α} : a = a

rfl : a = a is the unique constructor of the equality type. This is the same as Eq.refl except that it takes a implicitly instead of explicitly.

This is a more powerful theorem than it may appear at first, because although the statement of the theorem is a = a, Lean will allow anything that is definitionally equal to that type. So, for instance, 2 + 2 = 4 is proven in Lean by rfl, because both sides are the same up to definitional equality.

🔗theorem
Eq.symm.{u} {α : Sort u} {a b : α} (h : a = b) : b = a
Eq.symm.{u} {α : Sort u} {a b : α} (h : a = b) : b = a

Equality is symmetric: if a = b then b = a.

Because this is in the Eq namespace, if you have a variable h : a = b, h.symm can be used as shorthand for Eq.symm h as a proof of b = a.

For more information: Equality

🔗theorem
Eq.trans.{u} {α : Sort u} {a b c : α} (h₁ : a = b) (h₂ : b = c) : a = c
Eq.trans.{u} {α : Sort u} {a b c : α} (h₁ : a = b) (h₂ : b = c) : a = c

Equality is transitive: if a = b and b = c then a = c.

Because this is in the Eq namespace, if you have variables or expressions h₁ : a = b and h₂ : b = c, you can use h₁.trans h₂ : a = c as shorthand for Eq.trans h₁ h₂.

For more information: Equality

🔗theorem
Eq.subst.{u} {α : Sort u} {motive : α Prop} {a b : α} (h₁ : a = b) (h₂ : motive a) : motive b
Eq.subst.{u} {α : Sort u} {motive : α Prop} {a b : α} (h₁ : a = b) (h₂ : motive a) : motive b

The substitution principle for equality. If a = b and P a holds, then P b also holds. We conventionally use the name motive for P here, so that you can specify it explicitly using e.g. Eq.subst (motive := fun x => x < 5) if it is not otherwise inferred correctly.

This theorem is the underlying mechanism behind the rw tactic, which is essentially a fancy algorithm for finding good motive arguments to usefully apply this theorem to replace occurrences of a with b in the goal or hypotheses.

For more information: Equality

🔗def
cast.{u} {α β : Sort u} (h : α = β) (a : α) : β
cast.{u} {α β : Sort u} (h : α = β) (a : α) : β

Cast across a type equality. If h : α = β is an equality of types, and a : α, then a : β will usually not typecheck directly, but this function will allow you to work around this and embed a in type β as cast h a : β.

It is best to avoid this function if you can, because it is more complicated to reason about terms containing casts, but if the types don't match up definitionally sometimes there isn't anything better you can do.

For more information: Equality

🔗theorem
congr.{u, v} {α : Sort u} {β : Sort v} {f₁ f₂ : α β} {a₁ a₂ : α} (h₁ : f₁ = f₂) (h₂ : a₁ = a₂) : f₁ a₁ = f₂ a₂
congr.{u, v} {α : Sort u} {β : Sort v} {f₁ f₂ : α β} {a₁ a₂ : α} (h₁ : f₁ = f₂) (h₂ : a₁ = a₂) : f₁ a₁ = f₂ a₂

Congruence in both function and argument. If f₁ = f₂ and a₁ = a₂ then f₁ a₁ = f₂ a₂. This only works for nondependent functions; the theorem statement is more complex in the dependent case.

For more information: Equality

🔗theorem
congrFun.{u, v} {α : Sort u} {β : α Sort v} {f g : (x : α) β x} (h : f = g) (a : α) : f a = g a
congrFun.{u, v} {α : Sort u} {β : α Sort v} {f g : (x : α) β x} (h : f = g) (a : α) : f a = g a

Congruence in the function part of an application: If f = g then f a = g a.

🔗theorem
congrArg.{u, v} {α : Sort u} {β : Sort v} {a₁ a₂ : α} (f : α β) (h : a₁ = a₂) : f a₁ = f a₂
congrArg.{u, v} {α : Sort u} {β : Sort v} {a₁ a₂ : α} (f : α β) (h : a₁ = a₂) : f a₁ = f a₂

Congruence in the function argument: if a₁ = a₂ then f a₁ = f a₂ for any (nondependent) function f. This is more powerful than it might look at first, because you can also use a lambda expression for f to prove that <something containing a₁> = <something containing a₂>. This function is used internally by tactics like congr and simp to apply equalities inside subterms.

For more information: Equality

🔗def
Eq.mp.{u} {α β : Sort u} (h : α = β) (a : α) : β
Eq.mp.{u} {α β : Sort u} (h : α = β) (a : α) : β

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.

🔗def
Eq.mpr.{u} {α β : Sort u} (h : α = β) (b : β) : α
Eq.mpr.{u} {α β : Sort u} (h : α = β) (b : β) : α

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.

syntaxCasting
term ::= ...
    | `h ▸ e` is a macro built on top of `Eq.rec` and `Eq.symm` definitions.
Given `h : a = b` and `e : p a`, the term `h ▸ e` has type `p b`.
You can also view `h ▸ e` as a "type casting" operation
where you change the type of `e` by using `h`.

The macro tries both orientations of `h`. If the context provides an
expected type, it rewrites the expected type, else it rewrites the type of e`.

See the Chapter "Quantifiers and Equality" in the manual
"Theorem Proving in Lean" for additional information.
term  term

当项的类型包含等式的一侧作为子项时,可以使用 运算符重写它。 如果等式的两边都出现在项的类型中,则左侧将被重写为右侧。

19.4.1. 平等证明的唯一性🔗

由于定义证明无关,命题等价 证明是唯一的:两个数学对象不能以不同的方式相等。

theorem Eq.unique {α : Sort u} (x y : α) (p1 p2 : x = y) : p1 = p2 := α:Sort ux:αy:αp1:x = yp2:x = yp1 = p2 All goals completed! 🐙

Streicher 的公理 K (Streicher, 1993)Thomas Streicher, 1993. Investigations into Intensional Type Theory. Habilitation, Ludwig-Maximilians-Universität München 也是定义证明无关性的结果,其计算规则也是如此。 Axiom K 是逻辑上等同于 Eq.unique 的原理,作为 命题等价 的替代 递归器 实现。

def K {α : Sort u} {motive : {x : α} x = x Sort v} (d : {x : α} motive (Eq.refl x)) (x : α) (z : x = x) : motive z := d example {α : Sort u} {a : α} {motive : {x : α} x = x Sort u} {d : {x : α} motive (Eq.refl x)} {Variable name `v` is not explicitly referenced. The binding can be removed (if unused) or named `_` (if used implicitly). Note: This linter can be disabled with `set_option linter.unusedVariables false`v : motive (Eq.refl a)} : K (motive := motive) d a rfl = d := α:Sort ua:αmotive:{x : α} x = x Sort ud:{x : α} motive v:motive K (fun {x} => d) a = d All goals completed! 🐙

19.4.2. 异质平等🔗

Heterogeneous equality is a version of 命题等价 that does not require that the two equated terms have the same type. 然而,使用 rfl 的版本证明这些项是相等的需要类型和项在定义上是相等的。 换句话说,它允许制定更多的陈述。

异构相等在实践中通常不如普通的 命题等价 方便。 由于不要求等式两边都具有相同的类型而提供了更大的灵活性,这意味着它具有更少的有用属性。 由于依赖模式匹配,经常会遇到这种情况:当准确反映相应控制流所需的普通等式假设类型不正确时,split、策略和函数归纳 将异构等式假设添加到上下文中。 在这些情况下,内置自动化别无选择,只能使用异构平等。

🔗inductive predicate
HEq.{u} {α : Sort u} : α {β : Sort u} β Prop
HEq.{u} {α : Sort u} : α {β : Sort u} β Prop

Heterogeneous equality. a b asserts that a and b have the same type, and casting a across the equality yields b, and vice versa.

You should avoid using this type if you can. Heterogeneous equality does not have all the same properties as Eq, because the assumption that the types of a and b are equal is often too weak to prove theorems of interest. One public important non-theorem is the analogue of congr: If f g and x y and f x and g y are well typed it does not follow that f x g y. (This does follow if you have f = g instead.) However if a and b have the same type then a = b and a b are equivalent.

Conventions for notations in identifiers:

  • The recommended spelling of in identifiers is heq.

Constructors

HEq.refl.{u} {α : Sort u} (a : α) : a  a

Reflexivity of heterogeneous equality.

syntaxHeterogeneous Equality
term ::= ...
    | Heterogeneous equality. `a ≍ b` asserts that `a` and `b` have the same
type, and casting `a` across the equality yields `b`, and vice versa.

You should avoid using this type if you can. Heterogeneous equality does not
have all the same properties as `Eq`, because the assumption that the types of
`a` and `b` are equal is often too weak to prove theorems of interest. One
public important non-theorem is the analogue of `congr`: If `f ≍ g` and `x ≍ y`
and `f x` and `g y` are well typed it does not follow that `f x ≍ g y`.
(This does follow if you have `f = g` instead.) However if `a` and `b` have
the same type then `a = b` and `a ≍ b` are equivalent.


Conventions for notations in identifiers:

 * The recommended spelling of `≍` in identifiers is `heq`.term  term

异构相等HEq x y可以写成x y

🔗def
HEq.rfl.{u} {α : Sort u} {a : α} : a a
HEq.rfl.{u} {α : Sort u} {a : α} : a a

A version of HEq.refl with an implicit argument.

Heterogeneous Equality

Vector α n 类型是 Array α 的包装,其中包括数组大小为 n 的证明。 附加 Vector 是关联的,但不能使用普通的 命题等价 直接说明这一事实:

variable {xs : Vector α l₁} {ys : Vector α l₂} {zs : Vector α l₃} set_option linter.unusedVariables false theorem Vector.append_associative : xs ++ (ys ++ zs) = Type mismatch xs ++ ys ++ zs has type Vector α (l₁ + l₂ + l₃) but is expected to have type Vector α (l₁ + (l₂ + l₃))(xs ++ ys) ++ zs := sorry All goals completed! 🐙

问题是自然数的加法结合性在命题上成立,但在定义上不成立:

Type mismatch
  xs ++ ys ++ zs
has type
  Vector α (l₁ + l₂ + l₃)
but is expected to have type
  Vector α (l₁ + (l₂ + l₃))

解决此问题的一种方法是在语句中使用自然数加法的结合律:

theorem declaration uses `sorry`Vector.append_associative' : xs ++ (ys ++ zs) = Nat.add_assoc _ _ _ ((xs ++ ys) ++ zs) := α:Type ul₁:Natl₂:Natl₃:Natxs:Vector α l₁ys:Vector α l₂zs:Vector α l₃xs ++ (ys ++ zs) = (xs ++ ys ++ zs) All goals completed! 🐙

然而,在某些情况下,此类证明陈述可能很难使用。

另一种是使用异构平等:

theorem declaration uses `sorry`Vector.append_associative : HEq (xs ++ (ys ++ zs)) ((xs ++ ys) ++ zs) := α:Type ul₁:Natl₂:Natl₃:Natxs:Vector α l₁ys:Vector α l₂zs:Vector α l₃xs ++ (ys ++ zs) xs ++ ys ++ zs All goals completed! 🐙

在这种情况下,简化器可以重写方程两边,而不必保留它们的类型。 然而,证明该定理确实需要最终证明长度仍然匹配。

theorem Vector.append_associative : HEq (xs ++ (ys ++ zs)) ((xs ++ ys) ++ zs) := α:Type ul₁:Natl₂:Natl₃:Natxs:Vector α l₁ys:Vector α l₂zs:Vector α l₃xs ++ (ys ++ zs) xs ++ ys ++ zs α:Type ul₁:Natl₂:Natl₃:Natys:Vector α l₂zs:Vector α l₃toArray✝:Array αsize_toArray✝:toArray✝.size = l₁mk toArray✝ size_toArray✝ ++ (ys ++ zs) mk toArray✝ size_toArray✝ ++ ys ++ zs; α:Type ul₁:Natl₂:Natl₃:Natzs:Vector α l₃toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₁toArray✝:Array αsize_toArray✝:toArray✝.size = l₂mk toArray✝¹ size_toArray✝¹ ++ (mk toArray✝ size_toArray✝ ++ zs) mk toArray✝¹ size_toArray✝¹ ++ mk toArray✝ size_toArray✝ ++ zs; α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃mk toArray✝² size_toArray✝² ++ (mk toArray✝¹ size_toArray✝¹ ++ mk toArray✝ size_toArray✝) mk toArray✝² size_toArray✝² ++ mk toArray✝¹ size_toArray✝¹ ++ mk toArray✝ size_toArray✝ α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃mk (toArray✝² ++ (toArray✝¹ ++ toArray✝)) mk (toArray✝² ++ (toArray✝¹ ++ toArray✝)) α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃l₁ + (l₂ + l₃) = l₁ + l₂ + l₃α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃ α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃l₁ + (l₂ + l₃) = l₁ + l₂ + l₃ All goals completed! 🐙 α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃ α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃ = α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃((toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + (l₂ + l₃)) = ((toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + l₂ + l₃) α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃ = All goals completed! 🐙 α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃((toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + (l₂ + l₃)) = ((toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + l₂ + l₃) α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃(toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + (l₂ + l₃) (toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + l₂ + l₃ α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃(toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + (l₂ + l₃) (toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + l₂ + l₃α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃(toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + l₂ + l₃ (toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + (l₂ + l₃) α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃(toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + (l₂ + l₃) (toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + l₂ + l₃α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃(toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + l₂ + l₃ (toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + (l₂ + l₃) α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃h:(toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + l₂ + l₃(toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + (l₂ + l₃) α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃h:(toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + (l₂ + l₃)(toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + l₂ + l₃α:Type ul₁:Natl₂:Natl₃:NattoArray✝²:Array αsize_toArray✝²:toArray✝.size = l₁toArray✝¹:Array αsize_toArray✝¹:toArray✝.size = l₂toArray✝:Array αsize_toArray✝:toArray✝.size = l₃h:(toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + l₂ + l₃(toArray✝² ++ (toArray✝¹ ++ toArray✝)).size = l₁ + (l₂ + l₃) All goals completed! 🐙
🔗def
HEq.elim.{u, v} {α : Sort u} {a : α} {p : α Sort v} {b : α} (h₁ : a b) (h₂ : p a) : p b
HEq.elim.{u, v} {α : Sort u} {a : α} {p : α Sort v} {b : α} (h₁ : a b) (h₂ : p a) : p b

HEq.ndrec variant

🔗def
HEq.ndrec.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} β Sort u1} (m : motive a) {β : Sort u2} {b : β} (h : a b) : motive b
HEq.ndrec.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} β Sort u1} (m : motive a) {β : Sort u2} {b : β} (h : a b) : motive b

Non-dependent recursor for HEq

🔗def
HEq.ndrecOn.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} β Sort u1} {β : Sort u2} {b : β} (h : a b) (m : motive a) : motive b
HEq.ndrecOn.{u1, u2} {α : Sort u2} {a : α} {motive : {β : Sort u2} β Sort u1} {β : Sort u2} {b : β} (h : a b) (m : motive a) : motive b

HEq.ndrec variant

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

Substitution with heterogeneous equality.

🔗theorem
eq_of_heq.{u} {α : Sort u} {a a' : α} (h : a a') : a = a'
eq_of_heq.{u} {α : Sort u} {a a' : α} (h : a a') : a = a'

If two heterogeneously equal terms have the same type, then they are propositionally equal.

🔗theorem
heq_of_eq.{u_1} {α✝ : Sort u_1} {a a' : α✝} (h : a = a') : a a'
heq_of_eq.{u_1} {α✝ : Sort u_1} {a a' : α✝} (h : a = a') : a a'

Propositionally equal terms are also heterogeneously equal.

🔗theorem
heq_of_eqRec_eq.{u} {α β : Sort u} {a : α} {b : β} (h₁ : α = β) (h₂ : h₁ a = b) : a b
heq_of_eqRec_eq.{u} {α β : Sort u} {a : α} {b : β} (h₁ : α = β) (h₂ : h₁ a = b) : a b

If casting a term with Eq.rec to another type makes it equal to some other term, then the two terms are heterogeneously equal.

🔗theorem
eqRec_heq.{u, v} {α : Sort u} {φ : α Sort v} {a a' : α} (h : a = a') (p : φ a) : Eq.recOn h p p
eqRec_heq.{u, v} {α : Sort u} {φ : α Sort v} {a a' : α} (h : a = a') (p : φ a) : Eq.recOn h p p

Rewriting inside φ using Eq.recOn yields a term that's heterogeneously equal to the original term.

🔗theorem
cast_heq.{u} {α β : Sort u} (h : α = β) (a : α) : cast h a a
cast_heq.{u} {α β : Sort u} (h : α = β) (a : α) : cast h a a

The result of casting a term with cast is heterogeneously equal to the original term.

🔗theorem
heq_of_heq_of_eq.{u} {α β : Sort u} {a : α} {b b' : β} (h₁ : a b) (h₂ : b = b') : a b'
heq_of_heq_of_eq.{u} {α β : Sort u} {a : α} {b b' : β} (h₁ : a b) (h₂ : b = b') : a b'

Heterogeneous equality precomposes with propositional equality.

🔗theorem
type_eq_of_heq.{u} {α β : Sort u} {a : α} {b : β} (h : a b) : α = β
type_eq_of_heq.{u} {α β : Sort u} {a : α} {b : β} (h : a b) : α = β

If two terms are heterogeneously equal then their types are propositionally equal.