如何在精益中定义相互归纳命题?

时间:2017-01-21 04:36:39

标签: dependent-type theorem-proving mutual-recursion lean

我尝试使用归纳数据类型的语法,但它收到错误消息 "相互归纳类型必须编译为具有依赖消除的基本归纳类型"

以下是我尝试在自然数字上定义命题evenodd的示例

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)

还有一个相关的问题:定义相互递归函数的语法是什么?我似乎无法在任何地方找到它。

1 个答案:

答案 0 :(得分:5)

我认为Lean会自动尝试创建递归器even.recodd.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

最好隐含Ce : ℕ → Prop even.induction_on Ce参数,但由于某种原因,精益无法推断它(最后看到引理,我们在哪里明确传递Ce,否则精益推断odd.induction_on与我们的目标无关)。情况与evenb对称。

  

定义相互递归函数的语法是什么?

正如本lean-user thread中所解释的,对相互递归函数的支持非常有限:

  

不支持任意相互递归函数,但支持一个非常简单的情况。   在我们定义了相互递归的类型之后,我们可以定义相互递归的函数来“镜像”这些类型的结构。

您可以在该主题中找到一个示例。但是,我们再次使用相同的add-a-switching-parameter方法模拟相互递归的函数。让我们模拟相互递归的布尔谓词oddbdef 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)

以下是如何使用上述所有内容的示例。让我们来证明一个简单的引理:

return [
    'add_melon' => 'boolean',
    'fruits'    => 'in:banana,apple,pineapple'
];