categories/00_Introduction.lhs

391 lines
10 KiB
Text
Raw Normal View History

2012-10-09 14:42:51 +00:00
## Introduction
2012-10-10 15:56:43 +00:00
%TODO{Do everything after the end}
2012-10-09 14:42:51 +00:00
Now, it is time to talk about Categories.
How this notion could help you and how it is easy to use with Haskell.
- What are categories?
- How to use them?
2012-10-10 15:56:43 +00:00
### Programming Paradigms
2012-10-09 14:42:51 +00:00
2012-10-10 15:56:43 +00:00
When you program, you resolve problems.
2012-10-09 14:42:51 +00:00
There are a lot of different means to resolve a problem.
2012-10-10 15:56:43 +00:00
Many different "school of thought"[^school] exists.
2012-10-09 14:42:51 +00:00
2012-10-10 15:56:43 +00:00
[^school]: Écoles de pensées
**Imperative paradigm**:
2012-10-09 14:42:51 +00:00
In programming, most people use the imperative paradigm.
You have an infinite number of cell and you can write things on them.
2012-10-10 15:56:43 +00:00
Of course, it is more complex with modern architecture, but the paradigm is the same.
Hidden somewhere, there is the model of the Turing machine.
2012-10-09 14:42:51 +00:00
2012-10-10 15:56:43 +00:00
**Functional paradigm**:
2012-10-09 14:42:51 +00:00
Another paradigm, is the functional paradigm.
This time, you don't write on cells, but instead you have a flow of data.
And you transform the flows in another flows... Mostly it looks like pipes.
I am a bit restrictive here. But generally this is how functional programming is perceived.
The main theory behind this paradigm is the Set theory.
You have a set and you go from one set to another set by using a function.
2012-10-10 15:56:43 +00:00
**Category paradigm**:
I believe there is another paradigm arising from Category theory.
Category theory feels both more general and powerful to help solve problems.
2012-10-09 14:42:51 +00:00
First, you must realize there are categories everywhere.
With the category theory you can find relationships between quantum physics,
topology, logic (both predicate and first order), programming.
Most of the time, the object your are programming with will form a category.
This is the promise from the Category Theory.
Another even better paradigm.
A paradigm with gates between many different domains.
## Get some intuition
We write down the definition first.
And will discuss about some categories.
2012-10-10 15:56:43 +00:00
<div style="display:none">
\\( \newcommand{\hom}{\mathrm{hom}} \\)
</div>
2012-10-09 14:42:51 +00:00
> **Definition**:
>
> A category \\(C\\) consist of:
>
> - A collection of _objects_ \\(ob(C)\\)
2012-10-10 15:56:43 +00:00
> - For every pair of objects \\((A,B)\\) a set \\(\hom(A,B)\\)
> of _morphisms_ \\(f:A→B\\) (Another notation for \\(f\in \hom(A,B)\\))
2012-10-09 14:42:51 +00:00
> - A composition operator \\(∘\\)
2012-10-18 15:51:57 +00:00
> which associate to each couple \\(f:A→B\\), \\(g:B→C\\) another morphism \\(g∘f:A→C\\).
2012-10-09 14:42:51 +00:00
>
> With the following properties
>
> - for each object \\(x\\) there is an identity morphism
> \\(id_x:x→x\\)
> s.t. for any morphism \\(f:A->B\\),
> \\(id_A∘f = f = f∘id_B\\)
2012-10-18 15:51:57 +00:00
> - for all triplet of morphisms \\(f:A->B\\), \\(g:B->C\\) and \\(h:C->D\\)
> \\( (h∘g)∘f = h∘(g∘f) \\)
<mpost title="Identity is left and right neutral element for ∘">
z0=origin;
z1=(2gu,0);
2012-10-09 14:42:51 +00:00
2012-10-18 15:51:57 +00:00
drawState(z0,btex $A$ etex);
drawState(z1,btex $B$ etex);
2012-10-11 14:14:46 +00:00
2012-10-18 15:51:57 +00:00
drawLoop(z0,btex $id_A$ etex);
drawLoop(z1,btex $id_B$ etex);
drawEdge(z0,z1,btex $f\circ id_A = f = id_B\circ f$ etex);
</mpost>
<mpost title="Associativity">
z0=origin;
z1=(gu,0);
z2=(2gu,0);
z3=(3gu,0);
drawState(z0,btex $A$ etex);
drawState(z1,btex $B$ etex);
drawState(z2,btex $C$ etex);
drawState(z3,btex $D$ etex);
drawEdge(z0,z1,btex $f$ etex);
drawEdge(z1,z2,btex $g$ etex);
drawEdge(z2,z3,btex $h$ etex);
drawoptions(withcolor blue);
drawEdgeWithAngle(z0,z2,btex $g\circ f$ etex,30);
drawoptions(withcolor yellow);
drawEdgeWithAngle(z1,z3,btex $h\circ g$ etex,-30);
drawoptions(withcolor red);
drawEdgeWithAngle(z0,z3,btex $(h\circ g)\circ f = h\circ (g\circ f)$ etex,45);
</mpost>
2012-10-11 14:14:46 +00:00
2012-10-10 15:56:43 +00:00
### Representation of Category
Representing Category is not just a game.
It will be _very_ important.
But in the same time, it will help you to gain intuition about categories.
A naïve representation (which can work in many cases) is to represent
a specific category as a directed graph.
Here is a first example of the representation of a category:
2012-10-18 15:51:57 +00:00
<mpost title="First Naïve Category Representation">
z0=origin;
z1=2/3(gu,gu);
z2=(4/3gu,0);
2012-10-10 15:56:43 +00:00
2012-10-18 15:51:57 +00:00
drawState(z0,btex $A$ etex);
drawState(z1,btex $B$ etex);
drawState(z2,btex $C$ etex);
2012-10-10 15:56:43 +00:00
2012-10-18 15:51:57 +00:00
drawEdge(z0,z1,btex $f$ etex);
drawEdge(z1,z2,btex $g$ etex);
drawEdge(z0,z2,btex $h$ etex);
2012-10-10 15:56:43 +00:00
2012-10-18 15:51:57 +00:00
drawLoop(z0,btex $id_A$ etex);
drawLoop(z1,btex $id_B$ etex);
drawLoop(z2,btex $id_C$ etex);
</mpost>
2012-10-10 15:56:43 +00:00
From this graph we can conclude without any ambiguity that:
2012-10-10 16:29:41 +00:00
\\[ob(C)=\\{A,B,C\\}\\]
2012-10-10 15:56:43 +00:00
and
2012-10-19 12:15:12 +00:00
\\[\hom(C)=\\{f,g,h,id_A,id_B,id_C\\}\\]
2012-10-10 15:56:43 +00:00
2012-10-19 12:15:12 +00:00
Instantaneously, we understand that we can get rid of all \\(id_i\\) arrows.
2012-10-10 15:56:43 +00:00
But in reality, we lack an important information.
What is \\(∘\\)?
Now, we can add informations to our previous representation.
We simply add a relation between 3 arrows that represent the composition.
2012-10-18 15:51:57 +00:00
<mpost title="Naïve Category Representation">
z0=origin;
z1=(gu,gu);
z2=(2gu,0);
2012-10-10 15:56:43 +00:00
2012-10-18 15:51:57 +00:00
drawState(z0,btex $A$ etex);
drawState(z1,btex $B$ etex);
drawState(z2,btex $C$ etex);
2012-10-12 15:11:55 +00:00
2012-10-18 15:51:57 +00:00
drawEdge(z0,z1,btex $f$ etex);
drawEdge(z1,z2,btex $g$ etex);
drawEdge(z0,z2,btex $h$ etex);
2012-10-10 15:56:43 +00:00
2012-10-18 15:51:57 +00:00
drawoptions( withcolor red );
2012-10-10 15:56:43 +00:00
2012-10-18 15:51:57 +00:00
z3=.6[z0,z1];
z4=.6[z2,z1];
2012-10-10 15:56:43 +00:00
2012-10-18 15:51:57 +00:00
draw z3 -- z4 dashed evenly;
2012-10-10 16:29:41 +00:00
2012-10-18 15:51:57 +00:00
z5 = .45[z3,z4];
z6 = .55[z0,z2];
path bigarrow;
bigarrow := subpath (.1,.9) of z5 -- z6;
drawarrow bigarrow withpen pencircle scaled 1.5;
2012-10-10 15:56:43 +00:00
2012-10-18 15:51:57 +00:00
label.rt(btex $h = g \circ f$ etex, .5[z5,z6]);
2012-10-10 15:56:43 +00:00
2012-10-18 15:51:57 +00:00
</mpost>
2012-10-10 15:56:43 +00:00
2012-10-10 16:38:03 +00:00
Now we have a complete representation.
2012-10-19 12:15:12 +00:00
We don't have to represent \\(id_i\\), we know there are there.
And we also don't have to represent composition implying \\(id_i\\) morphisms.
2012-10-10 16:38:03 +00:00
But, even this little graph look complex.
To show just how complex things can be;
we just double the number morphisms between different objects.
2012-10-10 15:56:43 +00:00
2012-10-19 12:15:12 +00:00
<mpost title="Naïve Category Representation Mess (∘ representation)">
z0=origin;
z1=(2gu,gu);
z2=(4gu,0);
2012-10-10 15:56:43 +00:00
2012-10-19 12:15:12 +00:00
drawState(z0,btex $A$ etex);
drawState(z1,btex $B$ etex);
drawState(z2,btex $C$ etex);
2012-10-10 15:56:43 +00:00
2012-10-19 12:15:12 +00:00
drawEdgeWithAngle(z0,z1,btex $f$ etex,35);
drawEdge(z0,z1,btex $f'$ etex);
drawEdgeWithAngle(z1,z2,btex $g$ etex,35);
drawEdge(z1,z2,btex $g'$ etex);
drawEdgeWithAngle(z0,z2,btex $h$ etex,-10);
drawEdgeWithAngle(z0,z2,btex $h'$ etex,-35);
2012-10-10 15:56:43 +00:00
2012-10-19 12:15:12 +00:00
def drawLink(expr f,g,h,l,propf,propg,proph,propfg) =
begingroup
pair midf,midg,midh,midfg;
midf=point propf of f;
midg=point propg of g;
2012-10-10 15:56:43 +00:00
2012-10-19 12:15:12 +00:00
path fg; fg:=midf .. midg;
draw fg dashed evenly;
2012-10-10 15:56:43 +00:00
2012-10-19 12:15:12 +00:00
midfg = point propfg of fg;
midh = point proph of h;
path bigarrow;
bigarrow := subpath (.1,.9) of midfg .. midh;
drawarrow bigarrow withpen pencircle scaled 1.5;
2012-10-10 15:56:43 +00:00
2012-10-19 12:15:12 +00:00
label.rt(l, point .5 of bigarrow);
endgroup;
enddef;
2012-10-10 15:56:43 +00:00
2012-10-19 12:15:12 +00:00
path f,fp,g,gp,h,hp;
2012-10-10 15:56:43 +00:00
2012-10-19 12:15:12 +00:00
f=edgeAngle(z0,z1,35);
fp=edge(z0,z1);
g=edgeAngle(z1,z2,35);
gp=edge(z1,z2);
h=edgeAngle(z0,z2,-10);
hp=edgeAngle(z0,z2,-35);
2012-10-10 15:56:43 +00:00
2012-10-19 12:15:12 +00:00
drawoptions( withcolor red );
drawLink(f,g,h,btex $g\circ f$ etex, .5,.5,.4,.3);
drawoptions( withcolor blue );
drawLink(fp,gp,h,btex $h=g'\circ f'$ etex, .5,.5,.55,.7);
drawoptions( withcolor yellow );
drawLink(f,gp,hp,btex $h'=g'\circ f$ etex, .5,.5,.1,.2);
drawoptions( withcolor green );
drawLink(fp,g,hp,btex $h'=g\circ f'$ etex, .5,.5,.9,.8);
2012-10-10 15:56:43 +00:00
2012-10-19 12:15:12 +00:00
</mpost>
2012-10-10 19:55:30 +00:00
2012-10-19 12:15:12 +00:00
Another representation of the preceding category:
2012-10-10 19:55:30 +00:00
2012-10-19 12:15:12 +00:00
<mpost title="Another representation">
z0=origin;
z1=(2gu,gu);
z2=(4gu,0);
2012-10-10 19:55:30 +00:00
2012-10-19 12:15:12 +00:00
drawState(z0,btex $A$ etex);
drawState(z1,btex $B$ etex);
drawState(z2,btex $C$ etex);
2012-10-11 14:14:46 +00:00
2012-10-19 12:15:12 +00:00
drawEdgeWithAngle(z0,z1,btex $f$ etex,35);
drawEdge(z0,z1,btex $f'$ etex);
drawEdgeWithAngle(z1,z2,btex $g$ etex,35);
drawEdge(z1,z2,btex $g'$ etex);
drawEdgeWithAngle(z0,z2,btex $h=g\circ f=g'\circ f'$ etex,-10);
drawEdgeWithAngle(z0,z2,btex $h'=g\circ f'=g'\circ f$ etex,-35);
</mpost>
2012-10-11 14:14:46 +00:00
### Examples
Which can be a valid category by choosing ∘ appropriately?
2012-10-11 14:18:08 +00:00
The identity morphisms are assumed.
2012-10-11 14:14:46 +00:00
2012-10-18 15:51:57 +00:00
<mpost title="This can be a valid category">
z0=(0,0);
z1=2(u,0);
z2=2(2u,0);
2012-10-11 14:14:46 +00:00
drawarrow nl_edge(z0,z1);
drawarrow nl_edge(z1,z2);
drawarrow nl_edgeAngle(z0,z2,50);
2012-10-11 14:14:46 +00:00
2012-10-18 15:51:57 +00:00
drawstate(z0);
drawstate(z1);
drawstate(z2);
</mpost>
2012-10-11 14:14:46 +00:00
2012-10-18 15:51:57 +00:00
<mpost title="Cannot be a category; no candidate for g∘f.">
z0=(0,0); z1=3(u,0); z2=3(2u,0);
drawstate(z0); drawstate(z1); drawstate(z2);
drawedge(z0,z1,btex $f$ etex);
drawedge(z1,z2,btex $g$ etex);
</mpost>
<mpost title="Also a possible valid category">
z0=(0,0); z1=(4u,0); z2=(2u,-3u);
drawstate(z0); drawstate(z1); drawstate(z2);
drawarrow nl_edgeAngle(z0,z1,35);
drawarrow nl_edgeAngle(z1,z0,-145);
drawarrow nl_edge(z0,z2);
drawarrow nl_edge(z1,z2);
2012-10-18 15:51:57 +00:00
</mpost>
<mpost title="Not a category; no \(A→C\) while there exists \(A→B\) and \(B→C\)">
z0=(0,0); z1=(gu,0); z2=(.5gu,-.75gu);
drawState(z0,btex $A$ etex);
drawState(z1,btex $B$ etex);
drawState(z2,btex $C$ etex);
drawarrow edgeAngle(z0,z1,35);
drawarrow edgeAngle(z1,z0,-145);
drawarrow edge(z1,z2);
drawarrow edge(z2,z0);
2012-10-18 15:51:57 +00:00
</mpost>
2012-10-11 14:14:46 +00:00
<mpost title="Cannot be a category ; no possible associative ∘<br/>\((h∘g)∘f=idB∘f=f≠h=h∘idA=h∘(g∘f)\)">
z0=origin;
z1=(gu,0);
drawState(z0,btex $A$ etex);
drawState(z1,btex $B$ etex);
drawEdgeWithAngle(z1,z0,btex $f$ etex,145);
drawEdge(z0,z1,btex $g$ etex);
drawEdgeWithAngle(z1,z0,btex $h$ etex,-145);
</mpost>
2012-10-11 14:14:46 +00:00
To continue to gain some intuition I will give some degenerated Category examples.
### Monoids
What are Monoids?
Things that you can operate a list of in any evaluation order and obtain the same result.
More precisely; let `l` be a list of elements of the monoid.
then
<code class="haskell">
foldl (<>) e l = foldr (<>) e l
</code>
Where `(<>)` is the monoid operation.
And `e` is the neutral element of the monoid.
Equivalently:
<code class="haskell">
((e <> x) <> y) <> z = x <> ( y <> ( z <> e) )
</code>
Or another way of saying it is that `x <> y <> z` doesn't need any parenthesis.
Because whatever the order of evaluation the result will be the same.
Typical examples:
- `String` with `(++)` and `""`
- `Lists` with `(++)` and `[]`
- `Data.Text` with `append` and `empty`
- `Integer` with `(+)` and `0`
- `Integer` with `(*)` and `1`
- Generalized by `Monoid a` with `(<>)` and `mempty`
2012-10-18 15:51:57 +00:00
<mpost title="Strings are Categories">
u:=.5cm;
def drawloop(expr a,b,l) =
pair ba,ea;
path circ,p,s;
p:=a{1,1}..b..{1,-1}cycle;
circ:= fullcircle scaled 6 shifted a;
ba = circ intersectionpoint (subpath (0,1) of p);
ea = circ intersectionpoint (subpath (1,2) of p);
s:= ba{1,1}..b..{1,-1}ea;
drawarrow s;
label.top(l,b);
enddef;
pair A,B,C,D,E,F;
A:=(0,0);
B:=(0,u);
C:=(0,2u);
D:=(0,3u);
E:=(0,4u);
F:=(0,6u);
drawloop(A,B,btex $\varepsilon$ etex);
drawloop(A,C,btex $a$ etex);
drawloop(A,D,btex $b$ etex);
drawloop(A,E,btex $ab$ etex);
drawloop(A,F,btex $\omega$ etex);
draw (0,4.8u)--(0,5.8u) dashed withdots;
draw A withpen pencircle scaled 4bp;
2012-10-12 15:11:55 +00:00
</mpost>