如何定义精益中的互感命题?
How to define mutual inductive propositions in Lean?
我尝试使用归纳数据类型的语法,但收到错误消息 "mutually inductive types must compile to basic inductive type with dependent elimination".
下面是我尝试在自然数上定义命题 even
和 odd
的示例
mutual inductive even, odd
with even: ℕ → Prop
| z: even 0
| n: ∀ n, odd n → even (n + 1)
with odd: ℕ → Prop
| z: odd 1
| n: ∀ n, even n → odd (n + 1)
还有一个相关问题:定义相互递归函数的语法是什么?我似乎无法在任何地方找到它的记录。
我认为精益自动尝试创建递归 even.rec
和 odd.rec
来与 Type
一起工作,而不是 Prop
。但这行不通,因为精益将逻辑世界 (Prop
) 和计算世界 (Type
) 分开了。换句话说,我们只能破坏一个逻辑项(证明)来产生一个逻辑项。请注意,如果您将 even
和 odd
设为 ℕ → Type
.
类型,那么您的示例将起作用
作为相关系统的 Coq 证明助手通过创建两个(相当弱且不切实际的)归纳原理自动处理这种情况,但它当然不会生成一般的递归。
Lean wiki article 中描述了一种解决方法。它涉及编写大量样板文件。让我举例说明如何处理这种情况。
首先,我们将互归纳类型编译成一个归纳族。我们添加一个表示均匀度的布尔索引:
inductive even_odd: bool → ℕ → Prop
| ze: even_odd tt 0
| ne: ∀ n, even_odd ff n → even_odd tt (n + 1)
| zo: even_odd ff 1
| no: ∀ n, even_odd tt n → even_odd ff (n + 1)
接下来,我们定义一些缩写来模拟互感类型:
-- types
def even := even_odd tt
def odd := even_odd ff
-- constructors
def even.z : even 0 := even_odd.ze
def even.n (n : ℕ) (o : odd n): even (n + 1) := even_odd.ne n o
def odd.z : odd 1 := even_odd.zo
def odd.n (n : ℕ) (e : even n): odd (n + 1) := even_odd.no n e
现在,让我们推出我们自己的归纳原则:
-- induction principles
def even.induction_on {n : ℕ} (ev : even n) (Ce : ℕ → Prop) (Co : ℕ → Prop)
(ce0 : Ce 0) (stepe : ∀ n : ℕ, Co n → Ce (n + 1))
(co1 : Co 1) (stepo : ∀ n : ℕ, Ce n → Co (n + 1)) : Ce n :=
@even_odd.rec (λ (switch : bool), bool.rec_on switch Co Ce)
ce0 (λ n _ co, stepe n co)
co1 (λ n _ ce, stepo n ce)
tt n ev
def odd.induction_on {n : ℕ} (od : odd n) (Co : ℕ → Prop) (Ce : ℕ → Prop)
(ce0 : Ce 0) (stepe : ∀ n : ℕ, Co n → Ce (n + 1))
(co1 : Co 1) (stepo : ∀ n : ℕ, Ce n → Co (n + 1)) :=
@even_odd.rec (λ (switch : bool), bool.rec_on switch Co Ce)
ce0 (λ n _ co, stepe n co)
co1 (λ n _ ce, stepo n ce)
ff n od
最好让even.induction_on
的Ce : ℕ → Prop
参数隐式化,但由于某些原因精益无法推断它(见最后的引理,我们必须通过Ce
明确,否则精益推断 Ce
与我们的目标无关)。情况与odd.induction_on
.
对称
What is the syntax for defining mutually recursive functions?
如本 lean-user thread 中所述,对相互递归函数的支持非常有限:
there is no support for arbitrary mutually recursive functions, but there is support for a very simple case.
After we define a mutually recursive types, we can define mutually recursive functions that “mirror” the structure of these types.
您可以在该线程中找到示例。但是,同样,我们可以使用相同的 add-a-switching-parameter 方法模拟相互递归函数。让我们模拟相互递归的布尔谓词 evenb
和 oddb
:
def even_oddb : bool → ℕ → bool
| tt 0 := tt
| tt (n + 1) := even_oddb ff n
| ff 0 := ff
| ff (n + 1) := even_oddb tt n
def evenb := even_oddb tt
def oddb := even_oddb ff
这是一个如何使用上述所有内容的示例。让我们证明一个简单的引理:
lemma even_implies_evenb (n : ℕ) : even n -> evenb n = tt :=
assume ev : even n,
even.induction_on ev (λ n, evenb n = tt) (λ n, oddb n = tt)
rfl
(λ (n : ℕ) (IH : oddb n = tt), IH)
rfl
(λ (n : ℕ) (IH : evenb n = tt), IH)
我尝试使用归纳数据类型的语法,但收到错误消息 "mutually inductive types must compile to basic inductive type with dependent elimination".
下面是我尝试在自然数上定义命题 even
和 odd
的示例
mutual inductive even, odd
with even: ℕ → Prop
| z: even 0
| n: ∀ n, odd n → even (n + 1)
with odd: ℕ → Prop
| z: odd 1
| n: ∀ n, even n → odd (n + 1)
还有一个相关问题:定义相互递归函数的语法是什么?我似乎无法在任何地方找到它的记录。
我认为精益自动尝试创建递归 even.rec
和 odd.rec
来与 Type
一起工作,而不是 Prop
。但这行不通,因为精益将逻辑世界 (Prop
) 和计算世界 (Type
) 分开了。换句话说,我们只能破坏一个逻辑项(证明)来产生一个逻辑项。请注意,如果您将 even
和 odd
设为 ℕ → Type
.
作为相关系统的 Coq 证明助手通过创建两个(相当弱且不切实际的)归纳原理自动处理这种情况,但它当然不会生成一般的递归。
Lean wiki article 中描述了一种解决方法。它涉及编写大量样板文件。让我举例说明如何处理这种情况。
首先,我们将互归纳类型编译成一个归纳族。我们添加一个表示均匀度的布尔索引:
inductive even_odd: bool → ℕ → Prop
| ze: even_odd tt 0
| ne: ∀ n, even_odd ff n → even_odd tt (n + 1)
| zo: even_odd ff 1
| no: ∀ n, even_odd tt n → even_odd ff (n + 1)
接下来,我们定义一些缩写来模拟互感类型:
-- types
def even := even_odd tt
def odd := even_odd ff
-- constructors
def even.z : even 0 := even_odd.ze
def even.n (n : ℕ) (o : odd n): even (n + 1) := even_odd.ne n o
def odd.z : odd 1 := even_odd.zo
def odd.n (n : ℕ) (e : even n): odd (n + 1) := even_odd.no n e
现在,让我们推出我们自己的归纳原则:
-- induction principles
def even.induction_on {n : ℕ} (ev : even n) (Ce : ℕ → Prop) (Co : ℕ → Prop)
(ce0 : Ce 0) (stepe : ∀ n : ℕ, Co n → Ce (n + 1))
(co1 : Co 1) (stepo : ∀ n : ℕ, Ce n → Co (n + 1)) : Ce n :=
@even_odd.rec (λ (switch : bool), bool.rec_on switch Co Ce)
ce0 (λ n _ co, stepe n co)
co1 (λ n _ ce, stepo n ce)
tt n ev
def odd.induction_on {n : ℕ} (od : odd n) (Co : ℕ → Prop) (Ce : ℕ → Prop)
(ce0 : Ce 0) (stepe : ∀ n : ℕ, Co n → Ce (n + 1))
(co1 : Co 1) (stepo : ∀ n : ℕ, Ce n → Co (n + 1)) :=
@even_odd.rec (λ (switch : bool), bool.rec_on switch Co Ce)
ce0 (λ n _ co, stepe n co)
co1 (λ n _ ce, stepo n ce)
ff n od
最好让even.induction_on
的Ce : ℕ → Prop
参数隐式化,但由于某些原因精益无法推断它(见最后的引理,我们必须通过Ce
明确,否则精益推断 Ce
与我们的目标无关)。情况与odd.induction_on
.
What is the syntax for defining mutually recursive functions?
如本 lean-user thread 中所述,对相互递归函数的支持非常有限:
there is no support for arbitrary mutually recursive functions, but there is support for a very simple case. After we define a mutually recursive types, we can define mutually recursive functions that “mirror” the structure of these types.
您可以在该线程中找到示例。但是,同样,我们可以使用相同的 add-a-switching-parameter 方法模拟相互递归函数。让我们模拟相互递归的布尔谓词 evenb
和 oddb
:
def even_oddb : bool → ℕ → bool
| tt 0 := tt
| tt (n + 1) := even_oddb ff n
| ff 0 := ff
| ff (n + 1) := even_oddb tt n
def evenb := even_oddb tt
def oddb := even_oddb ff
这是一个如何使用上述所有内容的示例。让我们证明一个简单的引理:
lemma even_implies_evenb (n : ℕ) : even n -> evenb n = tt :=
assume ev : even n,
even.induction_on ev (λ n, evenb n = tt) (λ n, oddb n = tt)
rfl
(λ (n : ℕ) (IH : oddb n = tt), IH)
rfl
(λ (n : ℕ) (IH : evenb n = tt), IH)