我想将程序结构化为抽象模块,并编写使用抽象类型的函数。但我无法使用match
来破坏抽象类型,所以我必须创建某种反转引理,但我也不能match
。我试图将我的问题归结为:
首先创建一个可由Module Type
类型使用的decidable
。
Require Import Decidable.
Module Type decType.
Parameter T : Type.
Axiom decT : forall (a b:T), decidable (a=b).
End decType.
以下是一个示例:nat
是可判定的。但目的是编写plus
等仅解决抽象类型。 (我已删除参数zero
,Succ
及其要求,以使此示例最小化。
Require Peano_dec.
Module nat_dec <: decType.
Definition T := nat.
Definition decT := Peano_dec.dec_eq_nat.
End nat_dec.
现在回答我的问题:我想在decType
模块上编写参数化模块,其函数如果true
则返回a=b
,否则返回false
。由于a
和b
属于decType
,因此这应该是可判定的(因此可计算,或?),但如何编写beq
?
Module decBool (M: decType).
Import M.
Definition beq (a b:T) : bool :=
???
.
End decBool.
到目前为止,我的想法是我必须在decType模块类型中添加一个布尔函数,如下所示:
Module Type decType.
Parameter T : Type.
Axiom decT : forall (a b:T), decidable (a=b).
Parameter decB : forall (a b:T), {a=b}+{a<>b}.
End decType.
然后在上面的decB
模块中定义nat_dec
。
这是人们必须做的事情(即定义函数decB)?是不是可以使用抽象的事实,即类型是可判定的,而不通过返回bool的函数?
答案 0 :(得分:4)
你不能写这个函数,因为Coq中的命题和计算对象是分开的(例如参见this answer)。
请注意,将decB
参数添加到模块会导致decidable
公理不必要,因为您可以使用{P} + {Q}
派生P \/ Q
。
我想补充一些相关的说明。首先,我会避免使用Coq模块系统来执行除命名空间和编写不透明定义之外的任何操作。如果要编写参数化定义,最好使用相关记录,例如
Record eqType := {
sort :> Type;
eqb : sort -> sort -> bool;
eqbP : forall x y, eqb x y = true <-> x = y
}.
这基本上是Ssreflect采取的方法。您可以使用规范结构(如Ssreflect确实)或类型类来更轻松地使用这些相关记录。
其次,您可以编写显式的消除函数,以避免诉诸match
。例如,nat_rect
函数允许您使用高阶参数在nat
上编写递归函数:
nat_rect : forall (T : nat -> Type),
(* value for 0 *)
T 0 ->
(* body for recursive call *)
(forall n, T n -> T (S n)) ->
forall n, T n.
为每种感应数据类型自动定义这些功能。它们涉及依赖类型,但您也可以使用它们进行非依赖类型的递归。虽然这样效率有点低,但您也可以通过传递它们忽略递归调用值的函数(在上面的例子中,第二个函数参数的T n
参数)来使用它们进行模式匹配。 p>