Search code examples
coqcategory-theory

Messing around with category theory


Motivation: I am attempting to study category theory while creating a Coq formalization of the ideas I find in whatever textbook I follow. In order to make this formalization as simple as possible, I figured I should identify objects with their identity arrow, so a category can be reduced to a set (class, type) of arrows X with a source mapping s:X->X, target mapping t:X->X, and composition mapping product : X -> X -> option X which is a partial mapping defined for t f = s g. Obviously the structure (X,s,t,product) should follow various properties. For the sake of clarity, I am spelling out the formalization I chose below, but there is no need to follow it I think in order to read my question:

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
    }
    .

I have no idea how practical this is and how far it will take me. I see this as an opportunity to learn category theory and Coq at the same time.

Problem: My first objective was to create a 'Category' which would resemble as much as possible the category Set. In a set theoretic framework, I would probably consider the class of triplets (a,b,f) where f is a map with domain a and range a subset of b. With this in mind I tried:

Record Arrow : Type := arrow
    {   dom  : Type
    ;   cod  : Type
    ;   arr  : dom -> cod
    }
    .

So that Arrow becomes my base type on which I could attempt building a structure of category. I start embedding Type into Arrow:

Definition id (a : Type) : Arrow := arrow a a (fun x => x).

which allows me to define the source and target mappings:

Definition domain (f:Arrow) : Arrow := id (dom f).
Definition codomain (f:Arrow) : Arrow := id (cod f). 

Then I move on to defining a composition on Arrow:

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.

However, this code is illegal as I get the error:

The term "f' x" has type "b" while it is expected to have type "b'".

Question: I have the feeling I am not going to get away with this, My using Type naively would take me to some sort of Russel paradox which Coq will not allow me to do. However, just in case, is there a way to define compose on Arrow?


Solution

  • Your encoding does not work in plain Coq because of the constructive nature of the theory: it is not possible to compare two sets for equality. If you absolutely want to follow this approach, Daniel's comment sketches a solution: you need to assume a strong classical principle to be able to check whether the endpoints of two arrows match, and then manipulate an equality proof to make Coq accept the definition.

    Another approach is to have separate types for arrows and objects, and use type dependency to express the compatibility requirement on arrow endpoints. This definition requires only three axioms, and considerably simplifies the construction of categories:

    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
    }.
    

    We can now define the category of sets and ask Coq to automatically prove the axioms for us.

    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)
    |}.
    

    (This does not lead to any circularity paradoxes, because of Coq's universe mechanism: Coq understands that the Type used in this definition is actually smaller than the one used to define category.)

    This encoding is sometimes inconvenient due to the lack of extensionality in Coq's theory, because it prevents certain axioms from holding. Consider the category of groups, for example, where the morphisms are functions that commute with the group operations. A reasonable definition for these morphisms could be as follows (assuming that there is some type group representing groups, with * denotes multiplication and 1 denotes the neutral element).

    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
    }.
    

    The problem is that the properties mor_1 and mor_m interfere with the notion of equality for elements of group_morphism, making the proofs for associativity and identity that worked for Sets break. There are two solutions:

    1. Adopt extra axioms into the theory so that the required properties still go through. In the above example, you would need proof irrelevance:

      proof_irrelevance : forall (P : Prop) (p q : P), p = q.

    2. Change the category axioms so that the identities are valid up to some equivalence relation specific to that category, instead of the plain Coq equality. This approach is followed here, for example.