我有以下问题,请查看代码。
(* 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
的子句。
我知道我需要对类型做一些工作,但我不明白我应该做什么。
答案 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 x
为None
来提供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
放在Set
或Type
中:
Theorem always_some: forall x, { y: A & f_opt x = Some y}.
...
Qed.
然后您可以执行以下操作(或使用refine
或Program
):
Definition f (x: B) : A :=
let s := always_some x in let (x0, _) := s in x0.