在Coq中构建类层次结构?

时间:2011-11-03 04:34:51

标签: functional-programming scope typeclass coq

我可以使用类型类型在Coq中天真地构建代数结构的层次结构。我在查找Coq语法和类型类语义方面遇到了一些麻烦。但是,我相信以下是半群,幺半群和交换幺半群的正确实现:

Class Semigroup {A : Type} (op : A -> A -> A) : Type := {
  op_associative : forall x y z : A, op x (op y z) = op (op x y) z
}.

Class Monoid `(M : Semigroup) (id : A) : Type := {
  id_ident_left  : forall x : A, op id x = x;
  id_ident_right : forall x : A, op x id = x
}.  

Class AbelianMonoid `(M : Monoid) : Type := {
  op_commutative : forall x y : A, op x y = op y x
}.

如果我理解正确,可以通过首先声明Monoid Semigroup的实例,然后在id : A上进行参数化来添加其他参数(例如,monoid的标识元素)。但是,为AbelianMonoid构建的记录中发生了奇怪的事情。

< Print Monoid.
    Record Monoid (A : Type) (op : A -> A -> A) (M : Semigroup op) 
    (id : A) : Type := Build_Monoid
    { id_ident_left : forall x : A, op id x = x;
      id_ident_right : forall x : A, op x id = x }

< Print AbelianMonoid.
    Record AbelianMonoid (A : Type) (op : A -> A -> A) 
    (M0 : Semigroup op) (id0 : A) (M : Monoid M0 id0) : 
    Type := Build_AbelianMonoid
      { op_commutative : forall x y : A, op x y = op y x }

当我尝试为半群构建一个类时发生了这种情况。我认为以下语法是正确的:

Class Semiring `(P : AbelianMonoid) `(M : Monoid) := {
    ...
}.

但是,我无法消除正确的运算符和标识元素的歧义。打印记录揭示了上述问题。所以我有两个问题:第一,如何正确地声明课程Monoid;第二,如何消除超类中函数的歧义?

我真正喜欢的是一个很好的资源,清楚地解释了Coq的类型类没有过时的语法。例如,我认为Hutton的书清楚地解释了Haskell中的类型类。

1 个答案:

答案 0 :(得分:5)

<强>参考文献:

Coq中类型类的规范引用 - 超出the manual - this paperthe thesis(法语)Matthieu Sozeau。在a recent papermy thesis中,研究级别的规范参考文献(具有不同的观点)较少。您还应该花一些时间在Freenode上的#coq频道,并订阅the mailing list

您的问题:

语法问题本身不是Classes,而是maximally inserted implicit argumentsMonoidAbelianMonoid 类型在您的定义中(隐式)参数化参数,按此顺序,包括域类型,操作和标识 - 由索引打印这些记录类型时,您看到的依赖产品已完全展开。当您提及相关产品时,它们会自动填充,而不需要它们的参数。

实际上,如果留给自己的设备,隐式参数解析将自动插入所需的参数参数(对于依赖于它们的两种产品:PM的类型)。您只需要通过指定各种标识符的变量来指定这些标识符之间的约束,在适当的时候区分:

Class Semiring A mul add `(P : AbelianMonoid A mul) `(M : Monoid A add) := {
}.

结果:

> Print Semiring.
Record Semiring (A : Type) (mul add : A -> A -> A) 
(M0 : Semigroup mul) (id0 : A) (M : Monoid M0 id0) 
(P : AbelianMonoid M) (M1 : Semigroup add) (id1 : A) 
(M : Monoid M1 id1) : Type := Build_Semiring {  }

For Semiring: Arguments M0, id0, M, M1, id1 are implicit and maximally
              inserted
For Semiring: Argument scopes are [type_scope _ _ _ _ _ _ _ _ _]
For Build_Semiring: Argument scopes are [type_scope _ _ _ _ _ _ _ _ _]

注意阿贝尔幺半群和幺半群的身份这个时间是截然不同的。如果您对加法和乘法结构具有相同的标识元素,那么训练自己编写您想要的记录类型(也就是类)是一个很好的练习(即使它几乎没有数学意义)。