使用来自定理的信息进行模式匹配

时间:2017-06-07 12:56:55

标签: pattern-matching coq dependent-type convoy-pattern

我有以下问题,请查看代码。

  (* Suppose we have type A *)
  Variable A: Type.

  (* Also we have a function that returns the type (option A) *)
  Definition f_opt x: option A := ...

  (* Then, I can prove that this function always returns something: *)
  Theorem always_some: forall x, exists y, f_opt x = Some y.
  Admitted.

  (* Or, equivalently: *)
  Theorem always_not_none: forall x, f_opt x <> None.
  Admitted.

现在我想获得一个f_opt版本,它始终返回A类型的值。像这样:

  Definition f x: A :=
    match f_opt x with
      | Some y => y
    end.

但是我收到以下错误:

  

非详尽模式匹配:未找到模式None的子句。

我知道我需要对类型做一些工作,但我不明白我应该做什么。

3 个答案:

答案 0 :(得分:4)

在Coq的基础理论中,每个模式匹配都必须是详尽无遗的 - 也就是说,它必须明确地考虑所讨论的归纳类型的所有构造函数。这就是您收到所看到的错误消息的原因。

我们如何解决这个限制?有一些解决方案。首先,让我们看看如何说服Coq,None分支永远不会发生。为此,我们将使用您的always_not_none定理:

Definition f x : A :=
  match f_opt x as res return res <> None -> A with
  | Some y => fun _ => y
  | None => fun H => match H eq_refl with end
  end (always_not_none x).

这段代码乍一看可能看起来很奇怪,但它几乎可以执行您想要的模式匹配。为了向Coq解释None案例永远不会出现,它将always_not_none与该分支上f_opt x = None的事实结合起来以产生矛盾。这是该分支上的H eq_refl术语。然后,关于这个矛盾的match足以说服Coq分支是假的。更正式一点,因为False,矛盾命题是在没有任何构造函数的情况下定义的,当我们匹配False类型的术语时,没有要处理的分支,整个表达式可以返回我们想要的任何类型 - 在这种情况下,A

这段代码的奇怪之处在于匹配上的类型注释,并且它直接返回函数而不是类型A的函数。这样做是因为模式匹配在Coq中的依赖程度如何:每当我们想要使用从匹配的特定分支中获得的信息时(这里f_opt x等于None}在那个分支中),我们必须明确地让匹配返回一个函数 - Adam Chlipala称之为convoy pattern。这样做是为了让Coq知道您计划使用该额外信息的位置并检查它是否正确完成。在这里,我们使用f_opt xNone来提供always_not_none x导出矛盾所需的假设。

虽然这可以解决您的问题,但我通常会建议您不要这样做。例如,如果您知道某个元素A居住了a : A类型,那么您只需在该分支上f返回a即可。这样做的好处是可以避免在函数中提及证明,这通常会在简化和重写术语时受到妨碍。

答案 1 :(得分:4)

使用Coq的Program模块,您可以编写详尽的模式匹配,但注释某些分支应该无法到达,然后提供证明这种情况:

Require Import Program.
Program Definition f x : A :=
match f_opt x with
| Some a => a
| None => !
end.
Next Obligation.
destruct (always_some x). congruence.
Qed.

Program模块在​​幕后完成了很多工作,在完整的显式定义中,您必须使用“护送模式”进行编写。但请注意,有时{{1} }当涉及依赖类型时,往往会在Program和公理JMeq上生成大量依赖项,即使可能没有必要。)

答案 2 :(得分:1)

您需要将您的存在性证明always_not_none放在SetType中:

Theorem always_some: forall x, { y: A &  f_opt x = Some y}.
...
Qed.

然后您可以执行以下操作(或使用refineProgram):

Definition f (x: B) : A :=
   let s := always_some x in let (x0, _) := s in x0.