Skip to content

Commit 57f3394

Browse files
committed
palindrome を帰納的述語の例として追加する
resolve #2207
1 parent 4e873d7 commit 57f3394

File tree

1 file changed

+39
-0
lines changed

1 file changed

+39
-0
lines changed

LeanByExample/Declarative/Inductive.lean

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,45 @@ example {m n k : Nat} (h₁ : m ≤ₘ n) (h₂ : n ≤ₘ k) : m ≤ₘ k := by
140140
| @step l h₂ ih =>
141141
apply Nat.myle.step (by assumption)
142142

143+
/- #### 使用例: 回文判定
144+
145+
`Prop` 値の再帰関数として定義することと比較した、帰納的述語として定義することのメリットとして「定義における場合分けが簡潔になる」ことが挙げられます。以下は、リストが回文であることを主張する帰納的述語の例です。
146+
-/
147+
148+
variable {α : Type}
149+
150+
/-- 回文を表す帰納的述語 -/
151+
@[grind]
152+
inductive Palindrome : List α → Prop
153+
/-- 空リストは回文 -/
154+
| nil : Palindrome []
155+
/-- 要素が一つだけのリストは回文 -/
156+
| single (a : α) : Palindrome [a]
157+
/-- 回文の両端に同じ要素を追加しても回文 -/
158+
| sandwich {a : α} {as : List α} (ih : Palindrome as) : Palindrome ([a] ++ as ++ [a])
159+
160+
/-
161+
これと同様の定義を再帰関数によって行うことは可能ですが、`sandwich` のケースが少し複雑になってしまいます。これは、`match` 式が受け入れるパターンマッチの形式が限定されているためです。(`as.revers = as` で判定することもできますが、それが `Palindrome` と同値であることは自明ではないことです)
162+
-/
163+
164+
-- `DecidableEq` を仮定したくないので古典論理を利用する
165+
open scoped Classical in
166+
167+
/-- 回文判定を行う再帰関数 -/
168+
def isPalindrome (as : List α) : Prop :=
169+
match as with
170+
| [] => true
171+
| [a] => true
172+
| a₁ :: a₂ :: as =>
173+
let xs := (a₂ :: as).dropLast
174+
let x := (a₂ :: as).getLast (by simp)
175+
176+
if a₁ = x then
177+
isPalindrome xs
178+
else
179+
false
180+
termination_by as.length
181+
143182
/- #### 使用例: プログラムの BigStep 意味論
144183
145184
帰納的述語として定義することの更なるメリットとしては、再帰が停止することを保証しなくて良いことが挙げられます。実際、帰納的述語は本質的に停止する保証がない再帰的な操作でも扱うことができます。以下は、少し複雑ですがプログラムの BigStep 意味論を表現する例です。[^hitchhiker]

0 commit comments

Comments
 (0)