允许任意递归函数定义会使 Lean 的逻辑不一致。
一般递归使得编写循环证明成为可能:“命题P 为真,因为命题 P 为真”。
在证明之外,可以将无限循环分配为类型 Empty,它可以与 Lean.Parser.Term.nomatch : termEmpty match/ex falso. `nomatch e` is of arbitrary type `α : Sort u` if
Lean can show that an empty set of patterns is exhaustive given `e`'s type,
e.g. because it has no constructors.
nomatch 或 Empty.rec 一起使用来证明任何定理。
函数 countdown 在结构上是递归的。
The parameter n was matched against the pattern n'+1, which means that n' is a direct subterm of n in the second branch of the pattern match:
deffail to show termination forcountdown'with errorsfailed to infer structural recursion:Cannot use parameter n:failed to eliminate recursive applicationcountdown'n'failed to prove termination, possible solutions: - Use `have`-expressions to prove the remaining goals - Use `termination_by` to specify a different well-founded relation - Use `decreasing_by` to specify your own tactic for discharging this kind of goaln:Nath✝:¬(n==0)=truen':Nat := n-1⊢ n-1<ncountdown'(n:Nat):ListNat:=ifn==0then[]elseletn':=n-1n'::countdown'n'
fail to show termination forcountdown'with errorsfailed to infer structural recursion:Cannot use parameter n:failed to eliminate recursive applicationcountdown'n'failed to prove termination, possible solutions: - Use `have`-expressions to prove the remaining goals - Use `termination_by` to specify a different well-founded relation - Use `decreasing_by` to specify your own tactic for discharging this kind of goaln:Nath✝:¬(n==0)=truen':Nat := n-1⊢ n-1<n
Specify a termination measure for recursive functions.
```
termination_by a - b
```
indicates that termination of the currently defined recursive function follows
because the difference between the arguments `a` and `b` decreases.
If the function takes further argument after the colon, you can name them as follows:
```
def example (a : Nat) : Nat → Nat → Nat :=
termination_by b c => a - b
```
By default, a `termination_by` clause will cause the function to be constructed using well-founded
recursion. The syntax `termination_by structural a` (or `termination_by structural _ c => c`)
indicates the function is expected to be structural recursive on the argument. In this case
the body of the `termination_by` clause must be one of the function's parameters.
If omitted, a termination measure will be inferred. If written as `termination_by?`,
the inferred termination measure will be suggested.
terminationBy::= ...
|Specify a termination measure for recursive functions.
```
termination_by a - b
```
indicates that termination of the currently defined recursive function follows
because the difference between the arguments `a` and `b` decreases.
If the function takes further argument after the colon, you can name them as follows:
```
def example (a : Nat) : Nat → Nat → Nat :=
termination_by b c => a - b
```
By default, a `termination_by` clause will cause the function to be constructed using well-founded
recursion. The syntax `termination_by structural a` (or `termination_by structural _ c => c`)
indicates the function is expected to be structural recursive on the argument. In this case
the body of the `termination_by` clause must be one of the function's parameters.
If omitted, a termination measure will be inferred. If written as `termination_by?`,
the inferred termination measure will be suggested.
termination_bystructural(ident*=>)?term
defnotInductive(x:Nat→Nat):Nat:=notInductive(funn=>x(n+1))cannot use specified measure for structural recursion:its type is not an inductivetermination_bystructuralx
cannot use specified measure for structural recursion:its type is not an inductive
inductiveFin':Nat→Typewhere|zero:Fin'(n+1)|succ:Fin'n→Fin'(n+1)defconstantIndex(x:Fin'100):Nat:=constantIndex.zerocannot use specified measure for structural recursion:its type Fin' is an inductive family and indices are not variablesFin'100termination_bystructuralx
cannot use specified measure for structural recursion:its type Fin' is an inductive family and indices are not variablesFin'100
failed to infer structural recursion:Cannot use parameter x:failed to eliminate recursive applicationafterVarying(n+1)pWithParam'.zero
此外,函数的每次递归调用都必须在递减的 strict 子项上
参数。
递减参数本身是一个子项,但不是严格的子项。
如果子项是 Lean.Parser.Term.match : termPattern matching. `match e, ... with | p, ... => f | ...` matches each given
term `e` against each pattern `p` of a match alternative. When all patterns
of an alternative match, the `match` term evaluates to the value of the
corresponding right-hand side `f` with the pattern variables bound to the
respective matched values.
If used as `match h : e, ... with | p, ... => f | ...`, `h : e = p` is available
within `f`.
When not constructing a proof, `match` does not automatically substitute variables
matched on in dependent variables' types. Use `match (generalizing := true) ...` to
enforce this.
Syntax quotations can also be used in a pattern match.
This matches a `Syntax` value against quotations, pattern variables, or `_`.
Quoted identifiers only match identical identifiers - custom matching such as by the preresolved
names only should be done explicitly.
`Syntax.atom`s are ignored during matching by default except when part of a built-in literal.
For users introducing new atoms, we recommend wrapping them in dedicated syntax kinds if they
should participate in matching.
For example, in
```lean
syntax "c" ("foo" <|> "bar") ...
```
`foo` and `bar` are indistinguishable during matching, but in
```lean
syntax foo := "foo"
syntax "c" (foo <|> "bar") ...
```
they are not.
match 表达式或其他模式匹配语法的 判别式,则与判别式匹配的模式是每个 匹配替代项 的 右侧 中的子项。
特别是,匹配泛化的规则用于将判别式连接到右侧模式项的出现;因此,它尊重 定义等价。
当且仅当判别式是严格子项时,该模式才是严格子项。
如果子项是应用于参数的构造函数,则其递归参数是严格子项。
Nested Patterns and Sub-Terms
在以下示例中,递减参数 n 与嵌套模式 .succ(.succn) 进行匹配。因此,.succ(.succn) 是 n 的(非严格)子术语,因此 n 和 .succn 都是严格子术语,并且定义被接受。
Matching on Complex Expressions Can Prevent Elaboration
在以下示例中,递减参数 n 并不直接是 Lean.Parser.Term.match : termPattern matching. `match e, ... with | p, ... => f | ...` matches each given
term `e` against each pattern `p` of a match alternative. When all patterns
of an alternative match, the `match` term evaluates to the value of the
corresponding right-hand side `f` with the pattern variables bound to the
respective matched values.
If used as `match h : e, ... with | p, ... => f | ...`, `h : e = p` is available
within `f`.
When not constructing a proof, `match` does not automatically substitute variables
matched on in dependent variables' types. Use `match (generalizing := true) ...` to
enforce this.
Syntax quotations can also be used in a pattern match.
This matches a `Syntax` value against quotations, pattern variables, or `_`.
Quoted identifiers only match identical identifiers - custom matching such as by the preresolved
names only should be done explicitly.
`Syntax.atom`s are ignored during matching by default except when part of a built-in literal.
For users introducing new atoms, we recommend wrapping them in dedicated syntax kinds if they
should participate in matching.
For example, in
```lean
syntax "c" ("foo" <|> "bar") ...
```
`foo` and `bar` are indistinguishable during matching, but in
```lean
syntax foo := "foo"
syntax "c" (foo <|> "bar") ...
```
they are not.
match 表达式的 判别式。
因此,n' 不被视为 n 的子术语。
failed to infer structural recursion:Cannot use parameter n:failed to eliminate recursive applicationhalfn'defhalf(n:Nat):Nat:=matchOption.somenwith|.some(n'+2)=>halfn'+1|_=>0termination_bystructuraln
failed to infer structural recursion:Cannot use parameter n:failed to eliminate recursive applicationhalfn'
failed to infer structural recursion:Cannot use parameter #2:failed to eliminate recursive applicationlistLenxs.taildeflistLen:Listα→Nat|[]=>0|xs=>listLenxs.tail+1termination_bystructuralxs=>xs
Simultaneous Matching vs Matching Pairs for Structural Recursion
用于证明终止的策略的一个重要结果是两个 判别式的同时匹配并不等于匹配一对。
同时匹配保持判别式和模式之间的联系,允许模式匹配细化本地上下文中的假设类型以及 Lean.Parser.Term.match : termPattern matching. `match e, ... with | p, ... => f | ...` matches each given
term `e` against each pattern `p` of a match alternative. When all patterns
of an alternative match, the `match` term evaluates to the value of the
corresponding right-hand side `f` with the pattern variables bound to the
respective matched values.
If used as `match h : e, ... with | p, ... => f | ...`, `h : e = p` is available
within `f`.
When not constructing a proof, `match` does not automatically substitute variables
matched on in dependent variables' types. Use `match (generalizing := true) ...` to
enforce this.
Syntax quotations can also be used in a pattern match.
This matches a `Syntax` value against quotations, pattern variables, or `_`.
Quoted identifiers only match identical identifiers - custom matching such as by the preresolved
names only should be done explicitly.
`Syntax.atom`s are ignored during matching by default except when part of a built-in literal.
For users introducing new atoms, we recommend wrapping them in dedicated syntax kinds if they
should participate in matching.
For example, in
```lean
syntax "c" ("foo" <|> "bar") ...
```
`foo` and `bar` are indistinguishable during matching, but in
```lean
syntax foo := "foo"
syntax "c" (foo <|> "bar") ...
```
they are not.
match 的预期类型。
本质上,Lean.Parser.Term.match : termPattern matching. `match e, ... with | p, ... => f | ...` matches each given
term `e` against each pattern `p` of a match alternative. When all patterns
of an alternative match, the `match` term evaluates to the value of the
corresponding right-hand side `f` with the pattern variables bound to the
respective matched values.
If used as `match h : e, ... with | p, ... => f | ...`, `h : e = p` is available
within `f`.
When not constructing a proof, `match` does not automatically substitute variables
matched on in dependent variables' types. Use `match (generalizing := true) ...` to
enforce this.
Syntax quotations can also be used in a pattern match.
This matches a `Syntax` value against quotations, pattern variables, or `_`.
Quoted identifiers only match identical identifiers - custom matching such as by the preresolved
names only should be done explicitly.
`Syntax.atom`s are ignored during matching by default except when part of a built-in literal.
For users introducing new atoms, we recommend wrapping them in dedicated syntax kinds if they
should participate in matching.
For example, in
```lean
syntax "c" ("foo" <|> "bar") ...
```
`foo` and `bar` are indistinguishable during matching, but in
```lean
syntax foo := "foo"
syntax "c" (foo <|> "bar") ...
```
they are not.
match 的精化规则会特殊对待判别式,并且以保留程序运行时含义的方式更改判别式不一定会保留编译时含义。
failed to infer structural recursion:Cannot use parameter n:failed to eliminate recursive applicationmin'n'k'defmin'(nk:Nat):Nat:=match(n,k)with|(0,_)=>0|(_,0)=>0|(n'+1,k'+1)=>min'n'k'+1termination_bystructuraln
failed to infer structural recursion:Cannot use parameter n:failed to eliminate recursive applicationmin'n'k'
failed to infer structural recursion:Cannot use parameter nk:the type Nat×Nat does not have a `.brecOn` recursordefmin'(nk:Nat×Nat):Nat:=matchnkwith|(0,_)=>0|(_,0)=>0|(n'+1,k'+1)=>min'(n',k')+1termination_bystructuralnk
failed to infer structural recursion:Cannot use parameter nk:the type Nat×Nat does not have a `.brecOn` recursor
failed to infer structural recursion:Cannot use parameter n:failed to eliminate recursive applicationcountdown'(0+n')defcountdown'(n:Nat):ListNat:=matchnwith|0=>[]|n'+1=>n'::countdown'(0+n')termination_bystructuraln
failed to infer structural recursion:Cannot use parameter n:failed to eliminate recursive applicationcountdown'(0+n')
defadd'(n:Nat):=Nat.rec(motive:=fun_=>Nat)n(funVariable name `k` 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`ksoFar=>.succsoFar)
defhalf.match_1'.{u}:(motive:Nat→Sortu)→(x:Nat)→(Unit→motiveNat.zero)→(Unit→motive1)→((n:Nat)→motiven.succ.succ)→motivex:=funVariable name `motive` 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`motivexh_1h_2h_3=>Nat.casesOnx(h_1())funn=>Nat.casesOnn(h_2())funn=>h_3n
换句话说,half 中使用的模式的具体配置在 half.match_1 中捕获。
该定义是 half 预定义的更具可读性的版本:
defhalf':Nat→Nat:=fun(x:Nat)=>half.match_1(motive:=fun_=>Nat)x(fun_=>0)-- Case for 0(fun_=>0)-- Case for 1(funn=>Nat.succ(half'n))-- Case for n + 2
noncomputabledefhalf'':Nat→Nat:=fun(x:Nat)=>x.brecOnfunntable=>don't know how to synthesize placeholdercontext:xn:Nattable:Nat.belown⊢ Nat_/- To translate:
half.match_1 (motive := fun _ => Nat) x
(fun _ => 0) -- Case for 0
(fun _ => 0) -- Case for 1
(fun n => Nat.succ (half' n)) -- Case for n + 2
-/
noncomputabledefhalf'':Nat→Nat:=fun(x:Nat)=>x.brecOnfunntable=>(half.match_1(motive:=funk=>k.below(motive:=fun_=>Nat)→Nat)ndon't know how to synthesize placeholder for argument `h_1`context:xn:Nattable:Nat.belown⊢ Unit→Nat.belowNat.zero→Nat_don't know how to synthesize placeholder for argument `h_2`context:xn:Nattable:Nat.belown⊢ Unit→Nat.below1→Nat_don't know how to synthesize placeholder for argument `h_3`context:xn:Nattable:Nat.belown⊢ (n:Nat)→Nat.belown.succ.succ→Nat_)table/- To translate:
(fun _ => 0) -- Case for 0
(fun _ => 0) -- Case for 1
(fun n => Nat.succ (half' n)) -- Case for n + 2
-/
这三种情况的占位符需要以下类型:
don't know how to synthesize placeholder for argument `h_1`context:xn:Nattable:Nat.belown⊢ Unit→Nat.belowNat.zero→Nat
don't know how to synthesize placeholder for argument `h_2`context:xn:Nattable:Nat.belown⊢ Unit→Nat.below1→Nat
don't know how to synthesize placeholder for argument `h_3`context:xn:Nattable:Nat.belown⊢ (n:Nat)→Nat.belown.succ.succ→Nat
预定义中的前两种情况是常量函数,无需检查递归:
noncomputabledefhalf'':Nat→Nat:=fun(x:Nat)=>x.brecOnfunntable=>(half.match_1(motive:=funk=>k.below(motive:=fun_=>Nat)→Nat)n(fun()_=>.zero)(fun()_=>.zero)don't know how to synthesize placeholder for argument `h_3`context:xn:Nattable:Nat.belown⊢ (n:Nat)→Nat.belown.succ.succ→Nat_)table/- To translate:
(fun n => Nat.succ (half' n)) -- Case for n + 2
-/
值过程表中的第一个 Nat 是 n+1 的递归结果,第二个是 n 的递归结果。
因此,递归调用可以替换为查找,并且精化成功:
noncomputabledefhalf'':Nat→Nat:=fun(x:Nat)=>x.brecOnfunntable=>(half.match_1(motive:=funk=>k.below(motive:=fun_=>Nat)→Nat)n(fun()_=>.zero)(fun()_=>.zero)(fun_table=>Nat.succtable.2.1)tableunexpected end of input; expected ')', ',' or ':'
Specify a termination measure for recursive functions.
```
termination_by a - b
```
indicates that termination of the currently defined recursive function follows
because the difference between the arguments `a` and `b` decreases.
If the function takes further argument after the colon, you can name them as follows:
```
def example (a : Nat) : Nat → Nat → Nat :=
termination_by b c => a - b
```
By default, a `termination_by` clause will cause the function to be constructed using well-founded
recursion. The syntax `termination_by structural a` (or `termination_by structural _ c => c`)
indicates the function is expected to be structural recursive on the argument. In this case
the body of the `termination_by` clause must be one of the function's parameters.
If omitted, a termination measure will be inferred. If written as `termination_by?`,
the inferred termination measure will be suggested.
terminationBy::= ...
|Specify a termination measure for recursive functions.
```
termination_by a - b
```
indicates that termination of the currently defined recursive function follows
because the difference between the arguments `a` and `b` decreases.
If the function takes further argument after the colon, you can name them as follows:
```
def example (a : Nat) : Nat → Nat → Nat :=
termination_by b c => a - b
```
By default, a `termination_by` clause will cause the function to be constructed using well-founded
recursion. The syntax `termination_by structural a` (or `termination_by structural _ c => c`)
indicates the function is expected to be structural recursive on the argument. In this case
the body of the `termination_by` clause must be one of the function's parameters.
If omitted, a termination measure will be inferred. If written as `termination_by?`,
the inferred termination measure will be suggested.
termination_by(ident*=>)?term
Instances are used to prove that functions terminate using well-founded recursion by showing that
recursive calls reduce some measure according to a well-founded relation. This relation can combine
well-founded relations on the recursive function's parameters.
证明义务的上下文是递归调用的本地上下文。
特别是,局部假设(例如 if h : _、match h : _ with 或 have 引入的假设)可用。
如果函数参数是模式匹配的 判别式(例如,通过 Lean.Parser.Term.match : termPattern matching. `match e, ... with | p, ... => f | ...` matches each given
term `e` against each pattern `p` of a match alternative. When all patterns
of an alternative match, the `match` term evaluates to the value of the
corresponding right-hand side `f` with the pattern variables bound to the
respective matched values.
If used as `match h : e, ... with | p, ... => f | ...`, `h : e = p` is available
within `f`.
When not constructing a proof, `match` does not automatically substitute variables
matched on in dependent variables' types. Use `match (generalizing := true) ...` to
enforce this.
Syntax quotations can also be used in a pattern match.
This matches a `Syntax` value against quotations, pattern variables, or `_`.
Quoted identifiers only match identical identifiers - custom matching such as by the preresolved
names only should be done explicitly.
`Syntax.atom`s are ignored during matching by default except when part of a built-in literal.
For users introducing new atoms, we recommend wrapping them in dedicated syntax kinds if they
should participate in matching.
For example, in
```lean
syntax "c" ("foo" <|> "bar") ...
```
`foo` and `bar` are indistinguishable during matching, but in
```lean
syntax foo := "foo"
syntax "c" (foo <|> "bar") ...
```
they are not.
match 表达式),则该参数将被细化为证明义务中的匹配模式。
这里,termIfThenElse : term`if c then t else e` is notation for `ite c t e`, "if-then-else", which decides to
return `t` or `e` depending on whether `c` is true or false. The explicit argument
`c : Prop` does not have any actual computational content, but there is an additional
`[Decidable c]` argument synthesized by typeclass inference which actually
determines how to evaluate `c` to true or false. Write `if h : c then t else e`
instead for a "dependent if-then-else" `dite`, which allows `t`/`e` to use the fact
that `c` is true/false.
if 没有将关于条件(即,是否 n≤1)的本地假设添加到分支中的本地上下文。
Lean.Parser.Term.doFor : doElem`for x in e do s` iterates over `e` assuming `e`'s type has an instance of the `ForIn` typeclass.
`break` and `continue` are supported inside `for` loops.
`for x in e, x2 in e2, ... do s` iterates of the given collections in parallel,
until at least one of them is exhausted.
The types of `e2` etc. must implement the `Std.ToStream` typeclass.
for…Lean.Parser.Term.doFor : doElem`for x in e do s` iterates over `e` assuming `e`'s type has an instance of the `ForIn` typeclass.
`break` and `continue` are supported inside `for` loops.
`for x in e, x2 in e2, ... do s` iterates of the given collections in parallel,
until at least one of them is exhausted.
The types of `e2` etc. must implement the `Std.ToStream` typeclass.
in 循环体中的终止证明义务也得到了丰富,在本例中具有 Std.Legacy.Range 成员资格假设:
Extensible helper tactic for decreasing_tactic. This handles the "base case"
reasoning after applying lexicographic order lemmas.
It can be extended by adding more macro definitions, e.g.
String.Legacy.Iterator.sizeOf_next_lt_of_hasNext 和 String.Legacy.Iterator.sizeOf_next_lt_of_atEnd,使用 Lean.Parser.Term.doFor : doElem`for x in e do s` iterates over `e` assuming `e`'s type has an instance of the `ForIn` typeclass.
`break` and `continue` are supported inside `for` loops.
`for x in e, x2 in e2, ... do s` iterates of the given collections in parallel,
until at least one of them is exhausted.
The types of `e2` etc. must implement the `Std.ToStream` typeclass.
for 处理字符串迭代
defsynack:Nat→Nat→Nat|0,n=>n+1|m+1,0=>synackm1|m+1,n+1=>synackm(failed to prove termination, possible solutions: - Use `have`-expressions to prove the remaining goals - Use `termination_by` to specify a different well-founded relation - Use `decreasing_by` to specify your own tactic for discharging this kind of goalmn:Nat⊢ m/2+1<m+1synack(m/2+1)n)termination_bymn=>(m,n)
failed to prove termination, possible solutions: - Use `have`-expressions to prove the remaining goals - Use `termination_by` to specify a different well-founded relation - Use `decreasing_by` to specify your own tactic for discharging this kind of goalmn:Nat⊢ m/2+1<m+1
为了避免尝试所有度量元组的组合爆炸,Lean 首先将所有 基本终止度量 制成表格,确定基本度量是递减、严格递减还是非递减。
递减测度至少对于一次递归调用来说较小,并且在任何递归调用中都不会增加,而严格递减测度对于所有递归调用都较小。
非递减度量是终止策略无法显示递减或严格递减的度量。
根据表选择合适的元组。此方法基于 Lukas Bulwahn, Alexander Krauss, and Tobias Nipkow, 2007. “Finding Lexicographic Orders for Termination Proofs in Isabelle/HOL”. In Proceedings of the International Conference on Theorem Proving in Higher Order Logics (TPHOLS 2007). (LNTCS 4732)。
当找不到自动测量值时,此表会显示在错误消息中。
Could not find a decreasing measure.
The basic measures relate at each recursive call as follows:
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
n m l
1) 36:6-25 = = =
2) 37:6-23 = < _
3) 38:6-23 < _ _Please use `termination_by` to specify a decreasing measure.deff:(nml:Nat)→Nat|n+1,m+1,l+1=>[f(n+1)(m+1)(l+1),f(n+1)(m-1)(l),f(n)(m+1)(l)].sum|_,_,_=>0decreasing_byall_goalsdecreasing_tactic
Could not find a decreasing measure.
The basic measures relate at each recursive call as follows:
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
n m l
1) 36:6-25 = = =
2) 37:6-23 = < _
3) 38:6-23 < _ _Please use `termination_by` to specify a decreasing measure.
Could not find a decreasing measure.
The basic measures relate at each recursive call as follows:
(<, ≤, =: relation proved, ? all proofs failed, _: no proof attempted)
x1 x2
1) 643:16-23 ? ?
2) 644:27-40 _ _
3) 644:20-41 _ _Please use `termination_by` to specify a decreasing measure.defack:Nat→Nat→Nat|0,n=>n+1|m+1,0=>ackm1|m+1,n+1=>ackm(ack(m+1)n)decreasing_by·applyProd.Lex.leftomega·applyProd.Lex.rightomega·applyProd.Lex.leftomega
defnotAck:Nat→Nat→Nat|0,n=>n+1|m+1,0=>notAckm1|m+1,n+1=>notAckm(notAck(m/2+1)n)decreasing_byall_goalsfailed to prove termination, possible solutions: - Use `have`-expressions to prove the remaining goals - Use `termination_by` to specify a different well-founded relation - Use `decreasing_by` to specify your own tactic for discharging this kind of goalmn:Nat⊢ m/2+1<m+1All goals completed! 🐙
failed to prove termination, possible solutions: - Use `have`-expressions to prove the remaining goals - Use `termination_by` to specify a different well-founded relation - Use `decreasing_by` to specify your own tactic for discharging this kind of goalmn:Nat⊢ m/2+1<m+1
更准确地说,函数参数的每次出现都包含在 wfParam 中。
每当 Lean.Parser.Term.match : termPattern matching. `match e, ... with | p, ... => f | ...` matches each given
term `e` against each pattern `p` of a match alternative. When all patterns
of an alternative match, the `match` term evaluates to the value of the
corresponding right-hand side `f` with the pattern variables bound to the
respective matched values.
If used as `match h : e, ... with | p, ... => f | ...`, `h : e = p` is available
within `f`.
When not constructing a proof, `match` does not automatically substitute variables
matched on in dependent variables' types. Use `match (generalizing := true) ...` to
enforce this.
Syntax quotations can also be used in a pattern match.
This matches a `Syntax` value against quotations, pattern variables, or `_`.
Quoted identifiers only match identical identifiers - custom matching such as by the preresolved
names only should be done explicitly.
`Syntax.atom`s are ignored during matching by default except when part of a built-in literal.
For users introducing new atoms, we recommend wrapping them in dedicated syntax kinds if they
should participate in matching.
For example, in
```lean
syntax "c" ("foo" <|> "bar") ...
```
`foo` and `bar` are indistinguishable during matching, but in
```lean
syntax foo := "foo"
syntax "c" (foo <|> "bar") ...
```
they are not.
match 表达式将 any 判别式包装在 wfParam 中时,该小工具就会被删除,并且每次出现的模式匹配变量(无论它是否来自 wfParam 小工具的判别式)都会包装在 wfParam 中。
wfParam 设备也从 投影功能 应用程序中浮出。
attributePreprocessing Simp Set for Well-Founded Recursion
attr::= ...
|Theorems tagged with the `wf_preprocess` attribute are used during the processing of functions defined
by well-founded recursion. They are applied to the function's body to add additional hypotheses,
such as replacing `if c then _ else _` with `if h : c then _ else _` or `xs.map` with
`xs.attach.map`. Also see `wfParam`.
Warning: These rewrites are only applied to the declaration for the purpose of the logical
definition, but do not affect the compiled code. In particular they can cause a function definition
that diverges as compiled to be accepted without an explicit `partial` keyword, for example if they
remove irrelevant subterms or change the evaluation order by hiding terms under binders. Therefore
avoid tagging theorems with `[wf_preprocess]` unless they preserve also operational behavior.
wf_preprocess
Theorems tagged with the wf_preprocess attribute are used during the processing of functions defined
by well-founded recursion. They are applied to the function's body to add additional hypotheses,
such as replacing ifcthen_else_ with ifh:cthen_else_ or xs.map with
xs.attach.map. Also see wfParam.
Warning: These rewrites are only applied to the declaration for the purpose of the logical
definition, but do not affect the compiled code. In particular they can cause a function definition
that diverges as compiled to be accepted without an explicit partial keyword, for example if they
remove irrelevant subterms or change the evaluation order by hiding terms under binders. Therefore
avoid tagging theorems with [wf_preprocess] unless they preserve also operational behavior.
The wfParam gadget is used internally during the construction of recursive functions by
wellfounded recursion, to keep track of the parameter for which the automatic introduction
of List.attach (or similar) is plausible.
/-- A homogeneous pair -/structurePair(α:Typeu)wherefst:αsnd:α/-- Mapping a function over the elements of a pair -/defPair.map(f:α→β)(p:Pairα):Pairβwherefst:=fp.fstsnd:=fp.snd
/-- A binary tree defined using `Pair` -/inductiveTree(α:Typeu)where|leaf:α→Treeα|node:Pair(Treeα)→Treeα
map 函数的简单定义失败:
defTree.map(f:α→β):Treeα→Treeβ|leafx=>leaf(fx)|nodep=>node(p.map(funt'=>failed to prove termination, possible solutions: - Use `have`-expressions to prove the remaining goals - Use `termination_by` to specify a different well-founded relation - Use `decreasing_by` to specify your own tactic for discharging this kind of goalα:Type u_1p:Pair(Treeα)t':Treeα⊢ sizeOft'<1+sizeOfpt'.mapf))termination_byt=>t
failed to prove termination, possible solutions: - Use `have`-expressions to prove the remaining goals - Use `termination_by` to specify a different well-founded relation - Use `decreasing_by` to specify your own tactic for discharging this kind of goalα:Type u_1p:Pair(Treeα)t':Treeα⊢ sizeOft'<1+sizeOfp
A well-founded fixpoint. If satisfying the motive C for all values that are smaller according to a
well-founded relation allows it to be satisfied for the current value, then it is satisfied for all
values.
This function is used as part of the elaboration of well-founded recursion.
The inverse image of a well-founded relation is well-founded.
The function's body is passed to WellFounded.fix, with parameters suitably packed and unpacked, and recursive calls are replaced with a call to the value provided by WellFounded.fix.
Lean.Parser.Command.declaration : commanddecreasing_by策略生成的终止证明插入到正确的位置。
A relation r is WellFounded if all elements of α are accessible within r.
If a relation is WellFounded, it does not allow for an infinite descent along the relation.
If the arguments of the recursive calls in a function definition decrease according to
a well founded relation, then the function terminates.
Well-founded relations are sometimes called Artinian or said to satisfy the “descending chain condition”.
A value is accessible if for all y such that ryx, y is also accessible.
Note that if there exists no y such that ryx, then x is accessible. Such an x is called a
base case.
Division by Iterated Subtraction: Termination Proof
theoremdiv.eq0:divn0=0:=n:Nat⊢ divn0=0Tactic `rfl` failed: The left-hand sidedivn0is not definitionally equal to the right-hand side0n:Nat⊢ divn0=0n:Nat⊢ divn0=0
Tactic `rfl` failed: The left-hand sidedivn0is not definitionally equal to the right-hand side0n:Nat⊢ divn0=0
位于尾部位置的 Lean.Parser.Term.match : termPattern matching. `match e, ... with | p, ... => f | ...` matches each given
term `e` against each pattern `p` of a match alternative. When all patterns
of an alternative match, the `match` term evaluates to the value of the
corresponding right-hand side `f` with the pattern variables bound to the
respective matched values.
If used as `match h : e, ... with | p, ... => f | ...`, `h : e = p` is available
within `f`.
When not constructing a proof, `match` does not automatically substitute variables
matched on in dependent variables' types. Use `match (generalizing := true) ...` to
enforce this.
Syntax quotations can also be used in a pattern match.
This matches a `Syntax` value against quotations, pattern variables, or `_`.
Quoted identifiers only match identical identifiers - custom matching such as by the preresolved
names only should be done explicitly.
`Syntax.atom`s are ignored during matching by default except when part of a built-in literal.
For users introducing new atoms, we recommend wrapping them in dedicated syntax kinds if they
should participate in matching.
For example, in
```lean
syntax "c" ("foo" <|> "bar") ...
```
`foo` and `bar` are indistinguishable during matching, but in
```lean
syntax foo := "foo"
syntax "c" (foo <|> "bar") ...
```
they are not.
match 表达式的分支,
位于尾部位置的 termIfThenElse : term`if c then t else e` is notation for `ite c t e`, "if-then-else", which decides to
return `t` or `e` depending on whether `c` is true or false. The explicit argument
`c : Prop` does not have any actual computational content, but there is an additional
`[Decidable c]` argument synthesized by typeclass inference which actually
determines how to evaluate `c` to true or false. Write `if h : c then t else e`
instead for a "dependent if-then-else" `dite`, which allows `t`/`e` to use the fact
that `c` is true/false.
if 表达式的分支,以及
位于尾部位置的 Lean.Parser.Term.let : term`let` is used to declare a local definition. Example:
```
let x := 1
let y := x + 1
x + y
```
Since functions are first class citizens in Lean, you can use `let` to declare
local functions too.
```
let double := fun x => 2*x
double (double 3)
```
For recursive definitions, you should use `let rec`.
You can also perform pattern matching using `let`. For example,
assume `p` has type `Nat × Nat`, then you can write
```
let (x, y) := p
x + y
```
The *anaphoric let* `let := v` defines a variable called `this`.
let 表达式的主体。
特别是,Lean.Parser.Term.match : termPattern matching. `match e, ... with | p, ... => f | ...` matches each given
term `e` against each pattern `p` of a match alternative. When all patterns
of an alternative match, the `match` term evaluates to the value of the
corresponding right-hand side `f` with the pattern variables bound to the
respective matched values.
If used as `match h : e, ... with | p, ... => f | ...`, `h : e = p` is available
within `f`.
When not constructing a proof, `match` does not automatically substitute variables
matched on in dependent variables' types. Use `match (generalizing := true) ...` to
enforce this.
Syntax quotations can also be used in a pattern match.
This matches a `Syntax` value against quotations, pattern variables, or `_`.
Quoted identifiers only match identical identifiers - custom matching such as by the preresolved
names only should be done explicitly.
`Syntax.atom`s are ignored during matching by default except when part of a built-in literal.
For users introducing new atoms, we recommend wrapping them in dedicated syntax kinds if they
should participate in matching.
For example, in
```lean
syntax "c" ("foo" <|> "bar") ...
```
`foo` and `bar` are indistinguishable during matching, but in
```lean
syntax foo := "foo"
syntax "c" (foo <|> "bar") ...
```
they are not.
match 表达式的 判别式、termIfThenElse : term`if c then t else e` is notation for `ite c t e`, "if-then-else", which decides to
return `t` or `e` depending on whether `c` is true or false. The explicit argument
`c : Prop` does not have any actual computational content, but there is an additional
`[Decidable c]` argument synthesized by typeclass inference which actually
determines how to evaluate `c` to true or false. Write `if h : c then t else e`
instead for a "dependent if-then-else" `dite`, which allows `t`/`e` to use the fact
that `c` is true/false.
if 表达式的条件和函数的参数不是尾部位置。
defList.findIndex(xs:Listα)(p:α→Bool):Int:=matchxswith|[]=>-1|x::ys=>ifpxthen0elsehaver:=Could not prove 'List.findIndex' to be monotone in its recursive calls:Cannot eliminate recursive call `List.findIndex ys p` enclosed inifys✝.findIndexp=-1then-1elseys✝.findIndexp+1Tried to apply 'monotone_ite', but failed.Possible cause: A missing `MonoBind` instance.Use `set_option trace.Elab.Tactic.monotonicity true` to debug.List.findIndexyspifr=-1then-1elser+1partial_fixpoint
递归调用的错误消息是:
Could not prove 'List.findIndex' to be monotone in its recursive calls:Cannot eliminate recursive call `List.findIndex ys p` enclosed inifys✝.findIndexp=-1then-1elseys✝.findIndexp+1Tried to apply 'monotone_ite', but failed.Possible cause: A missing `MonoBind` instance.Use `set_option trace.Elab.Tactic.monotonicity true` to debug.
Could not prove 'List.findIndex' to be monotone in its recursive calls:Cannot eliminate recursive call `List.findIndex ys p` enclosed inmatchys✝.findIndexpwith|none=>none|somer=>some(r+1)
The least fixpoint of a monotone function is the least upper bound of its transfinite iteration.
The monotonef assumption is not strictly necessarily for the definition, but without this the
definition is not very meaningful and it simplifies applying theorems like fix_eq if every use of
fix already has the monotonicity requirement.
This is intended to be used in the construction of partial_fixpoint, and not meant to be used otherwise.
根据 Lean.Parser.Term.match : termPattern matching. `match e, ... with | p, ... => f | ...` matches each given
term `e` against each pattern `p` of a match alternative. When all patterns
of an alternative match, the `match` term evaluates to the value of the
corresponding right-hand side `f` with the pattern variables bound to the
respective matched values.
If used as `match h : e, ... with | p, ... => f | ...`, `h : e = p` is available
within `f`.
When not constructing a proof, `match` does not automatically substitute variables
matched on in dependent variables' types. Use `match (generalizing := true) ...` to
enforce this.
Syntax quotations can also be used in a pattern match.
This matches a `Syntax` value against quotations, pattern variables, or `_`.
Quoted identifiers only match identical identifiers - custom matching such as by the preresolved
names only should be done explicitly.
`Syntax.atom`s are ignored during matching by default except when part of a built-in literal.
For users introducing new atoms, we recommend wrapping them in dedicated syntax kinds if they
should participate in matching.
For example, in
```lean
syntax "c" ("foo" <|> "bar") ...
```
`foo` and `bar` are indistinguishable during matching, but in
```lean
syntax foo := "foo"
syntax "c" (foo <|> "bar") ...
```
they are not.
match 表达式进行拆分。
根据 termIfThenElse : term`if c then t else e` is notation for `ite c t e`, "if-then-else", which decides to
return `t` or `e` depending on whether `c` is true or false. The explicit argument
`c : Prop` does not have any actual computational content, but there is an additional
`[Decidable c]` argument synthesized by typeclass inference which actually
determines how to evaluate `c` to true or false. Write `if h : c then t else e`
instead for a "dependent if-then-else" `dite`, which allows `t`/`e` to use the fact
that `c` is true/false.
if 表达式进行拆分。
如果值和类型不依赖于 x,则将 Lean.Parser.Term.let : term`let` is used to declare a local definition. Example:
```
let x := 1
let y := x + 1
x + y
```
Since functions are first class citizens in Lean, you can use `let` to declare
local functions too.
```
let double := fun x => 2*x
double (double 3)
```
For recursive definitions, you should use `let rec`.
You can also perform pattern matching using `let`. For example,
assume `p` has type `Nat × Nat`, then you can write
```
let (x, y) := p
x + y
```
The *anaphoric let* `let := v` defines a variable called `this`.
let 表达式移至上下文。
当值和类型确实依赖于 x 时,对 Lean.Parser.Term.let : term`let` is used to declare a local definition. Example:
```
let x := 1
let y := x + 1
x + y
```
Since functions are first class citizens in Lean, you can use `let` to declare
local functions too.
```
let double := fun x => 2*x
double (double 3)
```
For recursive definitions, you should use `let rec`.
You can also perform pattern matching using `let`. For example,
assume `p` has type `Nat × Nat`, then you can write
```
let (x, y) := p
x + y
```
The *anaphoric let* `let := v` defines a variable called `this`.
let 表达式进行 Zeta 缩减。
使用 Lean.Parser.Command.coinductivecoinductive 命令,该命令提供镜像 Lean.Parser.Command.inductiveIn Lean, every concrete type other than the universes
and every type constructor other than dependent arrows
is an instance of a general family of type constructions known as inductive types.
It is remarkable that it is possible to construct a substantial edifice of mathematics
based on nothing more than the type universes, dependent arrow types, and inductive types;
everything else follows from those.
Intuitively, an inductive type is built up from a specified list of constructors.
For example, `List α` is the list of elements of type `α`, and is defined as follows:
```
inductive List (α : Type u) where
| nil
| cons (head : α) (tail : List α)
```
A list of elements of type `α` is either the empty list, `nil`,
or an element `head : α` followed by a list `tail : List α`.
See [Inductive types](https://lean-lang.org/theorem_proving_in_lean4/inductive_types.html)
for more information.
inductive 声明的声明性语法。
Could not prove 'NoInfChain' to be monotone in its recursive calls:Cannot eliminate recursive call inNoInfChainRy✝defNoInfChain(R:α→α→Prop)(x:α):Prop:=∀y,Rxy→¬NoInfChainRycoinductive_fixpoint
Could not prove 'NoInfChain' to be monotone in its recursive calls:Cannot eliminate recursive call inNoInfChainRy✝
对应的函数是:
defF(R:α→α→Prop)(x:α)(P:α→Prop):Prop:=∀y,Rxy→¬Py
Lean 未能证明这个函数是单调的,因为事实上它并不是单调的:
theoremF_nonmonotone:¬(∀αRPQ,(∀(x:α),Qx→Px)→(∀(x:α),FRxQ→FRxP)):=by⊢ ¬∀(α:Sort u_1)(R:α→α→Prop)(PQ:α→Prop),(∀(x:α),Qx→Px)→∀(x:α),FRxQ→FRxPsuffices∃αRPQ,¬((∀(x:α),Qx→Px)→(∀(x:α),FRxQ→FRxP))bythis:∃αRPQ,¬((∀(x:α),Qx→Px)→∀(x:α),FRxQ→FRxP)⊢ ¬∀(α:Sort u_1)(R:α→α→Prop)(PQ:α→Prop),(∀(x:α),Qx→Px)→∀(x:α),FRxQ→FRxPsimpa⊢ ∃αRPQ,¬((∀(x:α),Qx→Px)→∀(x:α),FRxQ→FRxP)-- α = PUnit, R always truerefine⟨PUnit,fun__=>True,?_⟩⊢ ∃PQ,¬((∀(x:PUnit),Qx→Px)→∀(x:PUnit),F(funxx_1=>True)xQ→F(funxx_1=>True)xP)-- P is trivially true, Q is always falserefine⟨fun_=>True,fun_=>False,?_⟩⊢ ¬((∀(x:PUnit),(funx=>False)x→(funx=>True)x)→∀(x:PUnit),(F(funxx_1=>True)xfunx=>False)→F(funxx_1=>True)xfunx=>True)simp[F]All goals completed! 🐙
defInfProd(α:Type):Prop:=α×Application type mismatch: The argumentInfProdαhas typePropof sort `Type` but is expected to have typeType ?u.3of sort `Type (?u.3 + 1)` in the applicationα×InfProdαInfProdαunused `coinductive_fixpoint`, function is not recursivecoinductive_fixpoint
错误消息表明需要一个提议:
Application type mismatch: The argumentInfProdαhas typePropof sort `Type` but is expected to have typeType ?u.3of sort `Type (?u.3 + 1)` in the applicationα×InfProdα
example(R:α→α→Prop)(a:α):InfSeqRa=∃b,Rab∧InfSeqRb:=byα:Sort u_1R:α→α→Propa:α⊢ InfSeqRa=∃b,Rab∧InfSeqRbTactic `rfl` failed: The left-hand sideInfSeqRais not definitionally equal to the right-hand side∃b,Rab∧InfSeqRbα:Sort u_1R:α→α→Propa:α⊢ InfSeqRa=∃b,Rab∧InfSeqRbrflα:Sort u_1R:α→α→Propa:α⊢ InfSeqRa=∃b,Rab∧InfSeqRb
Tactic `rfl` failed: The left-hand sideInfSeqRais not definitionally equal to the right-hand side∃b,Rab∧InfSeqRbα:Sort u_1R:α→α→Propa:α⊢ InfSeqRa=∃b,Rab∧InfSeqRb
在包含 Lean.Parser.Command.coinductivecoinductive 定义的 相互块 中,Lean.Parser.Command.inductiveIn Lean, every concrete type other than the universes
and every type constructor other than dependent arrows
is an instance of a general family of type constructions known as inductive types.
It is remarkable that it is possible to construct a substantial edifice of mathematics
based on nothing more than the type universes, dependent arrow types, and inductive types;
everything else follows from those.
Intuitively, an inductive type is built up from a specified list of constructors.
For example, `List α` is the list of elements of type `α`, and is defined as follows:
```
inductive List (α : Type u) where
| nil
| cons (head : α) (tail : List α)
```
A list of elements of type `α` is either the empty list, `nil`,
or an element `head : α` followed by a list `tail : List α`.
See [Inductive types](https://lean-lang.org/theorem_proving_in_lean4/inductive_types.html)
for more information.
inductive 关键字被重新解释:它不是注册为普通的内核归纳类型,而是通过晶格理论 感应固定点 机制进行详细说明。
这允许在同一个共同块中混合共归纳谓词和归纳谓词。
尚不支持通过 Lean.Parser.Term.match : termPattern matching. `match e, ... with | p, ... => f | ...` matches each given
term `e` against each pattern `p` of a match alternative. When all patterns
of an alternative match, the `match` term evaluates to the value of the
corresponding right-hand side `f` with the pattern variables bound to the
respective matched values.
If used as `match h : e, ... with | p, ... => f | ...`, `h : e = p` is available
within `f`.
When not constructing a proof, `match` does not automatically substitute variables
matched on in dependent variables' types. Use `match (generalizing := true) ...` to
enforce this.
Syntax quotations can also be used in a pattern match.
This matches a `Syntax` value against quotations, pattern variables, or `_`.
Quoted identifiers only match identical identifiers - custom matching such as by the preresolved
names only should be done explicitly.
`Syntax.atom`s are ignored during matching by default except when part of a built-in literal.
For users introducing new atoms, we recommend wrapping them in dedicated syntax kinds if they
should participate in matching.
For example, in
```lean
syntax "c" ("foo" <|> "bar") ...
```
`foo` and `bar` are indistinguishable during matching, but in
```lean
syntax foo := "foo"
syntax "c" (foo <|> "bar") ...
```
they are not.
match 的模式匹配;请改用 cases策略。
Restriction to Predicates
尝试定义不是谓词的共归纳类型会导致错误:
coinductive`coinductive` keyword can only be used to define predicatesMyNatwhere|zero:MyNat|succ:MyNat→MyNat
`coinductive` keyword can only be used to define predicates
While most Lean functions can be reasoned about in Lean's 类型论 as well as compiled and run, definitions marked partial or unsafe cannot be meaningfully reasoned about.
From the perspective of the logic, partial functions are opaque constants, and theorems that refer to unsafe definitions are summarily rejected.
作为无法使用这些函数进行推理的代价,对它们的要求要少得多; this can make it possible to write programs that would be impractical or cost-prohibitive to prove anything about, while not giving up formal reasoning for the rest.
In essence, the partial subset of Lean is a traditional functional programming language that is nonetheless deeply integrated with the theorem proving features, and the unsafe subset features the ability to break Lean's runtime invariants in certain rare situations, at the cost of less integration with Lean's theorem-proving特点。
类似地,noncomputable 定义可能使用在程序中没有意义但在逻辑中有意义的功能。
This function will cast a value of type α to type β, and is a no-op in the
compiler. This function is extremely dangerous because there is no guarantee
that types α and β have the same data representation, and this can lead to
memory unsafety. It is also logically unsound, since you could just cast
True to False. For all those reasons this function is marked as unsafe.
It is implemented by lifting both α and β into a common universe, and then
using cast(lcProof:ULift(PLiftα)=ULift(PLiftβ)) to actually perform
the cast. All these operations are no-ops in the compiler.
Using this function correctly requires some knowledge of the data representation
of the source and target types. Some general classes of casts which are safe in
the current runtime:
Arrayα to Arrayβ where α and β have compatible representations,
or more generally for other inductive types.
@Subtypeαp and α, or generally any structure containing only one
non-Prop field of type α.
Casting α to/from NonScalar when α is a boxed generic type
(i.e. a function that accepts an arbitrary type α and is not specialized to
a scalar type like UInt8).
Two objects are pointer-equal if, at runtime, they are allocated at exactly the same address. This
function is unsafe because it can distinguish between definitionally equal values.
Compares two lists of objects for element-wise pointer equality. Returns true if both lists are
the same length and the objects at the corresponding indices of each list are pointer-equal.
Two objects are pointer-equal if, at runtime, they are allocated at exactly the same address. This
function is unsafe because it can distinguish between definitionally equal values.
An object is exclusive if it is single-threaded and its reference counter is 1. This function is
unsafe because it can distinguish between definitionally equal values.
Executes arbitrary side effects in a pure context, with exceptions indicated via Except. This a
dangerous operation that can easily undermine important assumptions about the meaning of Lean
programs, and it should only be used with great care and a thorough understanding of compiler
internals, and even then only to implement observationally pure operations.
This function is not a good way to convert an EIOα or IOα into an α. Instead, use
do-notation.
Because the resulting value is treated as a side-effect-free term, the compiler may re-order,
duplicate, or delete calls to this function. The side effect may even be hoisted into a constant,
causing the side effect to occur at initialization time, even if it would otherwise never be called.
Executes arbitrary side effects in a pure context, with exceptions indicated via Except. This a
dangerous operation that can easily undermine important assumptions about the meaning of Lean
programs, and it should only be used with great care and a thorough understanding of compiler
internals, and even then only to implement observationally pure operations.
This function is not a good way to convert an EIOα or IOα into an α. Instead, use
do-notation.
Because the resulting value is treated as a side-effect-free term, the compiler may re-order,
duplicate, or delete calls to this function. The side effect may even be hoisted into a constant,
causing the side effect to occur at initialization time, even if it would otherwise never be called.
Executes arbitrary side effects in a pure context. This a dangerous operation that can easily
undermine important assumptions about the meaning of Lean programs, and it should only be used with
great care and a thorough understanding of compiler internals, and even then only to implement
observationally pure operations.
This function is not a good way to convert a BaseIOα into an α. Instead, use
do-notation.
Because the resulting value is treated as a side-effect-free term, the compiler may re-order,
duplicate, or delete calls to this function. The side effect may even be hoisted into a constant,
causing the side effect to occur at initialization time, even if it would otherwise never be called.
failed to synthesizeToStringClauseHint: Additional diagnostic information may be available using the `set_option diagnostics true` command.#synthToStringClause
failed to synthesizeToStringClauseHint: Additional diagnostic information may be available using the `set_option diagnostics true` command.
attribute[irreducible]Sequenceletxs:=Sequence.ofList[1,2,3];sorry : ?m.13#checkletxs:SequenceNat:=.ofList[1,2,3];xs.Invalid field `reverse`: The environment does not contain `Sequence.reverse`, so it is not possible to project the field `reverse` from an expressionxsof type `SequenceNat`reverse
Invalid field `reverse`: The environment does not contain `Sequence.reverse`, so it is not possible to project the field `reverse` from an expressionxsof type `SequenceNat`
theoremtally_eq_add:tallyxy=x+y:=byx:Naty:Nat⊢ tallyxy=x+yTactic `rfl` failed: The left-hand sidetallyxyis not definitionally equal to the right-hand sidex+yxy:Nat⊢ tallyxy=x+yrflx:Naty:Nat⊢ tallyxy=x+y
#checkfailed to synthesize instance of type classNonzero(tally22)Hint: Type class instance resolution failures can be inspected with the `set_option trace.Meta.synthInstance true` command.notZero(tally22)
failed to synthesize instance of type classNonzero(tally22)Hint: Type class instance resolution failures can be inspected with the `set_option trace.Meta.synthInstance true` command.
通过使用 Lean.Parser.Command.attribute : commandattribute 命令应用适当的属性,可以在定义定义的模块中全局修改定义的可约性。
在其他模块中,可以通过使用 local 修饰符应用属性来修改导入定义的可简化性。
Lean.Parser.commandSeal__ : commandThe `seal foo` command ensures that the definition of `foo` is sealed, meaning it is marked as `[irreducible]`.
This command is particularly useful in contexts where you want to prevent the reduction of `foo` in proofs.
In terms of functionality, `seal foo` is equivalent to `attribute [local irreducible] foo`.
This attribute specifies that `foo` should be treated as irreducible only within the local scope,
which helps in maintaining the desired abstraction level without affecting global settings.
seal 和 Lean.Parser.commandUnseal__ : commandThe `unseal foo` command ensures that the definition of `foo` is unsealed, meaning it is marked as `[semireducible]`, the
default reducibility setting. This command is useful when you need to allow some level of reduction of `foo` in proofs.
Functionally, `unseal foo` is equivalent to `attribute [local semireducible] foo`.
Applying this attribute makes `foo` semireducible only within the local scope.
unseal 命令是此过程的简写。
syntaxLocal Irreducibility
The sealfoo command ensures that the definition of foo is sealed, meaning it is marked as [irreducible].
This command is particularly useful in contexts where you want to prevent the reduction of foo in proofs.
In terms of functionality, sealfoo is equivalent to attribute[localirreducible]foo.
This attribute specifies that foo should be treated as irreducible only within the local scope,
which helps in maintaining the desired abstraction level without affecting global settings.
command::= ...
|The `seal foo` command ensures that the definition of `foo` is sealed, meaning it is marked as `[irreducible]`.
This command is particularly useful in contexts where you want to prevent the reduction of `foo` in proofs.
In terms of functionality, `seal foo` is equivalent to `attribute [local irreducible] foo`.
This attribute specifies that `foo` should be treated as irreducible only within the local scope,
which helps in maintaining the desired abstraction level without affecting global settings.
sealidentident*
syntaxLocal Reducibility
The unsealfoo command ensures that the definition of foo is unsealed, meaning it is marked as [semireducible], the
default reducibility setting. This command is useful when you need to allow some level of reduction of foo in proofs.
Functionally, unsealfoo is equivalent to attribute[localsemireducible]foo.
Applying this attribute makes foo semireducible only within the local scope.
command::= ...
|The `unseal foo` command ensures that the definition of `foo` is unsealed, meaning it is marked as `[semireducible]`, the
default reducibility setting. This command is useful when you need to allow some level of reduction of `foo` in proofs.
Functionally, `unseal foo` is equivalent to `attribute [local semireducible] foo`.
Applying this attribute makes `foo` semireducible only within the local scope.
unsealidentident*
enables users to modify the reducibility settings for declarations even when such changes are deemed potentially hazardous. For example, simp and type class resolution maintain term indices where reducible declarations are expanded.