Сер*_*жко 2 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.
Run Code Online (Sandbox Code Playgroud)
现在我想得到一个f_opt
总是返回 type 值的版本A
。像这样的东西:
Definition f x: A :=
match f_opt x with
| Some y => y
end.
Run Code Online (Sandbox Code Playgroud)
但我收到以下错误:
非详尽模式匹配:没有找到用于模式的子句
None
。
我知道我需要对类型做一些工作,但我不明白我到底应该做什么。
在 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).
Run Code Online (Sandbox Code Playgroud)
这段代码乍一看可能很奇怪,但它几乎可以执行您想要的模式匹配。为了向 Coq 解释这种None
情况永远不会出现,它结合always_not_none
了f_opt x = None
在该分支上推导出矛盾的事实。这是H eq_refl
那个分支上的术语。那么,match
这个矛盾就足以让 Coq 相信这个分支是虚假的。更正式一点,因为False
这个矛盾的命题是在没有任何构造函数的情况下定义的,当我们匹配一个 type 的术语时False
,没有分支需要处理,整个表达式可以返回我们想要的任何类型——在这种情况下, A
.
这段代码的奇怪之处在于匹配上的类型注释,它返回一个函数而不是A
直接返回类型的东西。这是因为依赖模式匹配在 Coq 中是如何工作的:每当我们想要利用我们从匹配的特定分支中获得的信息时(这里,它f_opt x
等于None
在那个分支中),我们必须明确地使match 返回一个函数——Adam Chlipala 称之为convoy 模式。这样做是为了让 Coq 知道你打算在哪里使用这些额外信息并检查它是否正确完成。在这里,我们使用 that f_opt x
isNone
来提供always_not_none x
推导矛盾所需的假设。
虽然这可以解决您的问题,但我通常会建议您不要这样做。例如,如果您知道您的A
类型由某个元素占据a : A
,那么您可以简单地在该分支上f
返回a
。这样做的好处是避免在函数中提及证明,这在简化和重写术语时经常会遇到障碍。
使用 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.
Run Code Online (Sandbox Code Playgroud)
(该Program
模块在幕后做了很多工作,在一个完整的显式定义中,您必须使用“convoy 模式”来编写。但是请注意,当依赖时,有时Program
往往会生成大量依赖JMeq
和公理JMeq_eq
涉及类型,即使可能没有必要。)