deffail to show termination for
countdown'
with errors
failed to infer structural recursion:
Cannot use parameter n:
failed to eliminate recursive application
countdown' 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 goal
n : Nat
h✝ : ¬(n == 0) = true
n' : Nat := n - 1
⊢ n - 1 < ncountdown'(n:Nat):ListNat:=ifn==0then[]elseletn':=n-1n'::countdown'n'
fail to show termination for
countdown'
with errors
failed to infer structural recursion:
Cannot use parameter n:
failed to eliminate recursive application
countdown' 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 goal
n : Nat
h✝ : ¬(n == 0) = true
n' : Nat := n - 1
⊢ n - 1 < n
Specify a termination argument 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 argument will be inferred. If written as `termination_by?`,
the inferrred termination argument will be suggested.
terminationBy::= ...
|Specify a termination argument 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 argument will be inferred. If written as `termination_by?`,
the inferrred termination argument will be suggested.
termination_bystructural(ident*=>)?term
defnotInductive(x:Nat→Nat):Nat:=notInductive(funn=>x(n+1))cannot use specified parameter for structural recursion:
its type is not an inductivetermination_bystructuralx
cannot use specified parameter 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 parameter for structural recursion:
its type Fin' is an inductive family and indices are not variables
Fin' 100termination_bystructuralx
cannot use specified parameter for structural recursion:
its type Fin' is an inductive family and indices are not variables
Fin' 100
inductiveWithParam'(p:Nat):Nat→Typewhere|zero:WithParam'p(n+1)|succ:WithParam'pn→WithParam'p(n+1)defafterVarying(n:Nat)(p:Nat)(x:WithParam'pn):Nat:=afterVarying(n+1)p.zerocannot use specified parameter for structural recursion:
its type is an inductive datatype
WithParam' p n
and the datatype parameter
p
depends on the function parameter
p
which does not come before the varying parameters and before the indices of the recursion parameter.termination_bystructuralx
cannot use specified parameter for structural recursion:
its type is an inductive datatype
WithParam' p n
and the datatype parameter
p
depends on the function parameter
p
which does not come before the varying parameters and before the indices of the recursion parameter.
部分項が 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 式やその他のパターンマッチ構文の 判別子 の場合、判別子にマッチするパターンは各 マッチ選択肢 の 右辺 の部分項です。特に マッチの一般化 の規則は、判別子を右辺におけるパターン項の出現に接続するために使用されます;つまり、 definitional equality を考慮します。判別子が厳密な部分項である場合に限り、パターンは 厳密な 部分項となります。
部分項が引数に適用されるコンストラクタである場合、その再帰的引数は厳密な部分項です。
入れ子のパターンと部分項
以下の例では、減少パラメータ n は入れ子のパターン .succ(.succn) にマッチします。したがって、 .succ(.succn) は n の(非厳密な)部分項であり、その結果 n と .succn はともに厳密な部分項であるため、この定義は受け入れられます。
以下の例では、減少パラメータ 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 application
half n'
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 application
half n'
failed to infer structural recursion:
Cannot use parameter #2:
failed to eliminate recursive application
listLen xs.tail
deflistLen:Listα→Nat|[]=>0|xs=>listLenxs.tail+1termination_bystructuralxs=>xs構造的再帰に対する同時マッチとマッチペア
停止性を証明するために使用される戦略の重要な帰結は、 2つの 判別子 の同時マッチはペアのマッチと同等ではない ということです。同時マッチは判別子とパターンの間の繋がりを維持し、その 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 application
min' 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 application
min' n' k'
failed to infer structural recursion:
Cannot use parameter nk:
the type Nat × Nat does not have a `.brecOn` recursor
defmin'(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
def'min'' has already been declaredmin'(nk:Nat×Nat):Nat:=matchnkwith|(0,_)=>0|(_,0)=>0|(n'+1,k'+1)=>min'(n',k')+1termination_bynk構造的再帰と definitional equality
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 placeholder
context:
x n : Nat
table : Nat.below n
⊢ 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
-/
次のステップは、もとの関数本体にある x を brecOn が提供する n で置き換えることです。table の型は x に依存するため、 half.match_1 でケースを分割する際にも一般化する必要があり、追加のパラメータを持つ同期となります。
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:
x n : Nat
table : Nat.below n
⊢ Unit → (fun k => Nat.below k → Nat) Nat.zero_don't know how to synthesize placeholder for argument 'h_2'
context:
x n : Nat
table : Nat.below n
⊢ Unit → (fun k => Nat.below k → Nat) 1_don't know how to synthesize placeholder for argument 'h_3'
context:
x n : Nat
table : Nat.below n
⊢ (n : Nat) → (fun k => Nat.below k → Nat) n.succ.succ_)table
/- To translate:
(fun _ => 0) -- Case for 0
(fun _ => 0) -- Case for 1
(fun n => Nat.succ (half' n)) -- Case for n + 2
-/
3つのケースのプレースホルダは以下の型を期待します:
don't know how to synthesize placeholder for argument 'h_1'
context:
x n : Nat
table : Nat.below n
⊢ Unit → (fun k => Nat.below k → Nat) Nat.zero
don't know how to synthesize placeholder for argument 'h_2'
context:
x n : Nat
table : Nat.below n
⊢ Unit → (fun k => Nat.below k → Nat) 1
don't know how to synthesize placeholder for argument 'h_3'
context:
x n : Nat
table : Nat.below n
⊢ (n : Nat) → (fun k => Nat.below k → Nat) n.succ.succ
事前定義にある最初の2つのケースは定数関数で、チェックする再帰はありません:
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:
x n : Nat
table : Nat.below n
⊢ (n : Nat) → (fun k => Nat.below k → Nat) n.succ.succ_)table
/- To translate:
(fun n => Nat.succ (half' n)) -- Case for n + 2
-/
累積テーブルの最初の Nat は n+1 に対する再帰の結果であり、2番目は 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 ':'