允许任意递归函数定义会使 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,即可“证明”任意定理。
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
递减参数类型中的参数,不能依赖那些位于变化参数或索引之后的函数形参。
在 afterVarying 中,固定前缀 为空,因为第一个形参 n 会变化,所以 p 不属于固定前缀:
failed to infer structural recursion:Cannot use parameter x:failed to eliminate recursive applicationafterVarying(n+1)pWithParam'.zero
此外,函数的每次递归调用都必须作用于递减参数的某个 真子项。
递减参数自身是一个子项,但不是真子项。
若某个子项是 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 并不是 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
用于证明终止性的这些策略有一个重要后果:同时匹配两个 判别项 与匹配一个二元组并不等价。
同时匹配会保留判别项与模式之间的联系,使模式匹配不仅能细化局部上下文中假设的类型,也能细化 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
在 countdown' 中,递归出现被应用到了 0+n' 上;它与 n' 并不定义相等,因为自然数上的加法是按照第二个参数做结构递归的:
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.Hint: The binding can be removed (if unused) or named `_` (if used implicitly). Alternatively, prefix the name with `_` to silence this warning:[apply]_kNote: 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.Hint: The binding can be removed (if unused) or named `_` (if used implicitly). Alternatively, prefix the name with `_` to silence this warning:[apply]_motiveNote: 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)-- 0 的分支(fun_=>0)-- 1 的分支(funn=>Nat.succ(half'n))-- 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/- 待翻译:
(fun _ => 0) -- 0 的分支
(fun _ => 0) -- 1 的分支
(fun n => Nat.succ (half' n)) -- 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/- 待翻译:
(fun n => Nat.succ (half' n)) -- 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
证明目标的上下文,就是该递归调用所在的局部上下文。
尤其是,局部假设(例如由 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` 是 `ite c t e`(即“如果—那么—否则”)的记法;它根据 `c` 是否为真返回 `t` 或 `e`。
显式参数 `c : Prop` 本身没有计算内容;另有一个由实例合成得到的 `[Decidable c]` 参数,真正决定如何把 `c` 求值为真或假。
写成 `if h : c then t else e` 时表示依赖式条件 `dite`,此时 `t` 和 `e` 可以使用 `c` 为真或假的事实。
标识符中的记法约定:建议将 `if c then t else e` 写作 `ite`,并分别用 `left`、`right` 指代 `t`、`e`。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 over 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 over 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 的成员资格假设:
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 over 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) 32:6-25 = = =
2) 33:6-23 = < _
3) 34: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) 32:6-25 = = =
2) 33:6-23 = < _
3) 34: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) 638:16-23 ? ?
2) 639:27-40 _ _
3) 639: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 表达式有任意一个判别项被 wfParam 包裹,这个小工具就会被移除,并且所有模式匹配变量的每次出现(无论它是否来自那个带有 wfParam 小工具的判别项)都会改为包上一层 wfParam。
此外,wfParam 小工具还会从 投影函数 应用中被上浮出来。
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
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
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` 是 `ite c t e`(即“如果—那么—否则”)的记法;它根据 `c` 是否为真返回 `t` 或 `e`。
显式参数 `c : Prop` 本身没有计算内容;另有一个由实例合成得到的 `[Decidable c]` 参数,真正决定如何把 `c` 求值为真或假。
写成 `if h : c then t else e` 时表示依赖式条件 `dite`,此时 `t` 和 `e` 可以使用 `c` 为真或假的事实。
标识符中的记法约定:建议将 `if c then t else e` 写作 `ite`,并分别用 `left`、`right` 指代 `t`、`e`。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` 是 `ite c t e`(即“如果—那么—否则”)的记法;它根据 `c` 是否为真返回 `t` 或 `e`。
显式参数 `c : Prop` 本身没有计算内容;另有一个由实例合成得到的 `[Decidable c]` 参数,真正决定如何把 `c` 求值为真或假。
写成 `if h : c then t else e` 时表示依赖式条件 `dite`,此时 `t` 和 `e` 可以使用 `c` 为真或假的事实。
标识符中的记法约定:建议将 `if c then t else e` 写作 `ite`,并分别用 `left`、`right` 指代 `t`、`e`。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)
对 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` 是 `ite c t e`(即“如果—那么—否则”)的记法;它根据 `c` 是否为真返回 `t` 或 `e`。
显式参数 `c : Prop` 本身没有计算内容;另有一个由实例合成得到的 `[Decidable c]` 参数,真正决定如何把 `c` 求值为真或假。
写成 `if h : c then t else e` 时表示依赖式条件 `dite`,此时 `t` 和 `e` 可以使用 `c` 为真或假的事实。
标识符中的记法约定:建议将 `if c then t else e` 写作 `ite`,并分别用 `left`、`right` 指代 `t`、`e`。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✝
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 策略。
仅限谓词
尝试定义一个并非谓词的余归纳类型会导致错误:
coinductive`coinductive` keyword can only be used to define predicatesMyNatwhere|zero:MyNat|succ:MyNat→MyNat
`coinductive` keyword can only be used to define predicates
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
classNonzero(n:Nat)wherenon_zero:n≠0instanceNonzero.instSucc:Nonzero(n+1)wherenon_zero:=byn:Nat⊢ n+1≠0grindAll goals completed! 🐙Definition `notZero` is a proposition; use `theorem` instead of `def`Note: This linter can be disabled with `set_option linter.defProp false`defnotZero(n:Nat)[Nonzeron]:n≠0:=Nonzero.non_zero
#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 命令是该流程的便捷写法。
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*
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*