动机:我正在尝试研究范畴理论,同时创建一个Coq形式化的概念,我发现在我遵循的任何教科书中。为了使这种形式化尽可能简单,我想我应该使用它们的标识箭头来标识对象,因此可以将一个类别缩减为具有源映射{{1}的箭头X
的集合(类,类型) },目标映射s:X->X
和组合映射t:X->X
,它是为product : X -> X -> option X
定义的部分映射。显然,结构t f = s g
应遵循各种属性。为了清楚起见,我正在阐述我在下面选择的形式化,但我认为没有必要遵循它来阅读我的问题:
(X,s,t,product)
我不知道这是多么实用,以及我需要走多远。我认为这是一个同时学习类别理论和Coq的机会。
问题:我的第一个目标是创建一个尽可能类似Record Category {A:Type} : Type := category
{ source : A -> A
; target : A -> A
; product: A -> A -> option A
; proof_of_ss : forall f:A, source (source f) = source f
; proof_of_ts : forall f:A, target (source f) = source f
; proof_of_tt : forall f:A, target (target f) = target f
; proof_of_st : forall f:A, source (target f) = target f
; proof_of_dom: forall f g:A, target f = source g <-> product f g <> None
; proof_of_src: forall f g h:A, product f g = Some h -> source h = source f
; proof_of_tgt: forall f g h:A, product f g = Some h -> target h = target g
; proof_of_idl: forall a f:A,
a = source a ->
a = target a ->
a = source f ->
product a f = Some f
; proof_of_idr: forall a f:A,
a = source a ->
a = target a ->
a = target f ->
product f a = Some f
; proof_of_asc:
forall f g h fg gh:A,
product f g = Some fg ->
product g h = Some gh ->
product fg h = product f gh
}
.
类别的“类别”。在集合理论框架中,我可能会考虑三元组Set
类,其中(a,b,f)
是具有域f
的映射,并且范围是a
的子集。考虑到这一点,我试过:
b
这样Record Arrow : Type := arrow
{ dom : Type
; cod : Type
; arr : dom -> cod
}
.
成为我可以尝试构建类别结构的基本类型。我开始将Type嵌入到Arrow中:
Arrow
允许我定义源映射和目标映射:
Definition id (a : Type) : Arrow := arrow a a (fun x => x).
然后我继续在Arrow上定义一个合成:
Definition domain (f:Arrow) : Arrow := id (dom f).
Definition codomain (f:Arrow) : Arrow := id (cod f).
但是,当我收到错误时,此代码是非法的:
Definition compose (f g: Arrow) : option Arrow :=
match f with
| arrow a b f' =>
match g with
| arrow b' c g' =>
match b with
| b' => Some (arrow a c (fun x => (g' (f' x))))
| _ => None
end
end
end.
问题:我觉得我不会侥幸逃脱这一点,我天真地使用The term "f' x" has type "b" while it is expected to have type "b'".
会带我去某种Russel悖论,Coq不允许我这样做做。但是,为了以防万一,有没有办法在Type
上定义compose
?
答案 0 :(得分:3)
由于理论的建设性,你的编码在普通Coq中不起作用:不可能比较两组的相等性。如果您绝对想要遵循这种方法,Daniel的评论草拟了一个解决方案:您需要假设一个强大的经典原则,以便能够检查两个箭头的端点是否匹配,然后操纵相等证明以使Coq接受定义。 / p>
另一种方法是为箭头和对象分别设置类型,并使用类型依赖关系来表示箭头端点的兼容性要求。这个定义只需要三个公理,大大简化了类别的构建:
Set Implicit Arguments.
Unset Strict Implicit.
Unset Printing Implicit Defensive.
Record category : Type := Category {
obj : Type;
hom : obj -> obj -> Type;
id : forall {X}, hom X X;
comp : forall X Y Z, hom X Y -> hom Y Z -> hom X Z;
(* Axioms *)
idL : forall X Y (f : hom X Y), comp id f = f;
idR : forall X Y (f : hom X Y), comp f id = f;
assoc : forall X Y Z W
(f : hom X Y) (g : hom Y Z) (h : hom Z W),
comp f (comp g h) = comp (comp f g) h
}.
我们现在可以定义集合的类别,并要求Coq自动为我们证明公理。
Require Import Coq.Program.Tactics.
Program Definition Sets : category := {|
obj := Type;
hom X Y := X -> Y;
id X := fun x => x;
comp X Y Z f g := fun x => g (f x)
|}.
(由于Coq的Universe机制,这不会导致任何循环悖论:Coq理解此定义中使用的Type
实际上小于用于定义category
的{{1}}。)
由于Coq理论缺乏可扩展性,这种编码有时不方便,因为它阻止了某些公理的存在。考虑组的类别,例如,态射是与群组操作通勤的功能。这些态射的合理定义可以如下(假设有一些类型group
代表组,*
表示乘法而1
表示中性元素。)
Record group_morphism (X Y : group) : Type := {
mor : X -> Y;
mor_1 : mor 1 = 1;
mor_m : forall x1 x2, mor (x1 * x2) = mor x1 * mor x2
}.
问题是,属性mor_1
和mor_m
会干扰group_morphism
元素的相等概念,从而使Sets
的关联性和身份证明成为可能打破。有两种解决方案:
在理论中采用额外的公理,以便所需的属性仍然存在。在上面的例子中,您需要证明不相关:
proof_irrelevance:forall(P:Prop)(p q:P),p = q。
更改类别公理,使标识有效,直至某个特定于该类别的等价关系,而不是普通的Coq相等。例如,此方法遵循here。