Teoria kategorii dla informatyków/Wykład 5: Funktory i transformacje naturalne

Z Studia Informatyczne
Przejdź do nawigacjiPrzejdź do wyszukiwania

Funktory

Definicja 5.1 [Funktor]

Funktor albo funktor kowariantny F:𝐂𝐃 z kategorii 𝐂 do kategorii 𝐃 jest dany poprzez:

  • operację przypisującą jednoznacznie każdemu obiektowi

X𝐂0 obiekt F(X)𝐃1

  • operację przypisującą jednoznacznie każdemu morfizmowi f𝐂1 morfizm F(f)𝐃1

w ten sposób, że:

  • jeśli f:XY w 𝐂, to F(f):F(X)F(Y) w 𝐃,
  • F(1X)=1F(X)
  • F(fg)=F(f)F(g).


Funktory typu 𝐂op𝐃 nazywamy często funktorami kontrawariantnymi, aby podkreślić, że jego dziedziną jest kategoria dualna do 𝐂.


Przykład 5.2 [funktor potęgowy]

Funktorem jest operacja 𝒫:𝐒𝐞𝐭𝐒𝐞𝐭 definiowana jako: 𝐗={BBX} dla X𝐂0 oraz dla morfizmu f:XY, 𝒫(f):𝒫(X)𝒫(Y) jest funkcją, która podzbiorowi Z zbioru X przyporządkowuje jego obraz f[Z], który jest podzbiorem Y.

Sprawdźmy, czy operacja 𝒫 spełnia warunki definicji funktora: po pierwsze, dla dowolnej identyczności 1X:XX, 𝒫(1X) jest funkcją, która każdemu podzbiorowi ZX przyporządkowuje obraz 1X[Z]=Z, czyli funkcja identycznościowa. A zatem 𝒫1X=1𝒫(X), czyli operacja 𝒫 zachowuje identyczności. Po drugie, dla dowolnej pary strzałek f:XY oraz g:YZ strzałka 𝒫(g)𝒫(f) typu 𝒫(X)𝒫(Z) jest z definicji złożeniem dwóch funkcji: AXf[A]Y oraz f[A]Yg[f[A]]Z, czyli tym samym co funkcja AX(gf)[A]Z (to prosta własność obrazów funkcji), czyli - z definicji - tym samym co funkcja 𝒫(gf). Dowiedliśmy w ten sposób, że 𝒫(gf)=𝒫(g)𝒫(f). A zatem 𝒫:𝐒𝐞𝐭𝐒𝐞𝐭 jest funktorem (kowariantnym).


Przykład 5.3

Mając dany zbiór S, oznaczmy przez List(S) zbiór wszystkich skończonych słów List złożonych z elementów S. Oczywiście lista pusta ε jest elementem List(S). Jeśli konkatenację list oznaczymy jako , to widzimy, że (List(S),,ε) jest monoidem. Niech 𝐌𝐨𝐧 oznacza kategorię monoidów i homomorfizmów monoidów. Pokażemy, że List:𝐒𝐞𝐭𝐌𝐨𝐧 jest funktorem. W tym celu zauważmy, że dla dowolnej funkcji F:SR, operację List(f):List(S)List(R) potrzebną do wyrażenia definicji List jako funktora, możemy zdefiniować jako funkcję przypisującą liście L=[s1,s2,,sn] listę f(L)=[f(s1),f(s2),,,f(sn)]. Własności konkatenacji implikują natychmiast, że List(f)(ε)=ε) oraz List(f)(L1L2)=List(f)(L1)List(f)(L2). Te dwa warunki stanowią świadectwo, że List(f) jest homomorfizmem monoidów, czyli morfizmem w 𝐌𝐨𝐧. Postawiona definicja określająca działanie operacji List na morfizmach jest więc poprawna. Pozostaje nam sprawdzenie, że List zachowuje identyczności (rzecz trywialna) i złożenia funkcji. W tym celu zauważmy, że List(fg)([s1,s2,...,sn])=[(fg)(s1),...,(fg)(sn)]=[(f(g(s1)),...,(f(g(sn))]=List(f)([g(s1),...,g(sn)])=List(f)(List(g)([s1,...,sn]))=(List(f)List(g))([s1,...,sn]), co świadczy o tym, że List(fg)=List(f)List(g). To kończy dowód faktu, że List:𝐒𝐞𝐭𝐌𝐨𝐧 jest funktorem.


Przykład 5.4

Niech K będzie pierścieniem przemiennym z jedynką. Zbiór wszystkich macierzy odwracalnych stopnia n wraz z operacją mnożenia macierzy tworzy grupę oznaczaną GLn(K). Ponieważ każdy homomorfizm pierścieni f:KL indukuje w sposób naturalny homomorfizm GLn(f):GLn(K)GLn(L), łatwo już sprawdzić, że dla każdego nωoperacja GLn jest funktorem z kategorii pierścieni przemiennych z jedynką 𝐂𝐑𝐧𝐠 do kategorii grup 𝐆𝐫𝐩.


Przykład 5.5

Niech (X,τ) będzie przestrzenią topologiczną. Oznaczmy poset wszystkich zbiorów otwartych uporządkowanych względem inkluzji jako Ω(X). Poset ten jest kratą zupełną (suprema to sumy, zaś infima to wnętrza przecięć), w której zachodzi prawo przemienności:
aS={assS}

dla dowolnych aΩ(X) i SΩ(x). Jeśli f:XY jest dowolną funkcją ciągłą pomiędzy przestrzeniami topologicznymi (X,τ) i (Y,σ), to przeciwobraz f1:Ω(Y)Ω(X) jest funkcją, która zachowuje (a co za tym idzie: funkcją monotoniczną) oraz (bo przeciwobrazy zachowują sumy zbiorów).

Powyższe rozważania motywują następujące definicje dwóch kategorii:

  • kategorii ram (ang. frames), oznaczanej 𝐅𝐫𝐦, której obiektami są kraty zupełne spełniające powyższe prawo nieskończonej przemienności, a morfizmami funkcje zachowujące skończone infima i dowolne suprema.
  • kategorii 𝐋𝐨𝐜 lokali (ang. locales), która jest dualna do 𝐅𝐫𝐦. Morfizmy 𝐋𝐨𝐜 nazywa się często w literaturze funkcjami ciągłymi. Teoria lokali rości sobie pretensje do tzw. konstruktywnej topologii, czyli teorii przestrzeni topologicznych, w której unika się rozważań niekonstruktywnych, korzystających z pewnika wyboru, jak i rozważań dotyczących elementów przestrzeni topologicznych; w zamian teoria lokali ofiaruje topologię w języku funkcji ciągłych i ich przekształceń. Więcej informacji na ten temat można znaleźć w (zaawansowanym pojęciowo) podręczniku pt. Stone Spaces autorstwa prof. P.T. Johnstone'a.

Mając dane powyższe definicje, widzimy już, że Ω:𝐓𝐨𝐩𝐋𝐨𝐜 jest funktorem.


Przykład 5.6 [funktory zapominania]

Niech 𝐂 będzie dowolną kategorią, w której obiektami są zbiory z pewną dodatkową strukturą (np. strukturą przestrzeni wektorowej, strukturą przestrzeni topologicznych, itp.), zaś morfizmami - funkcje, które zachowują tę strukturę (np. odwzorowania liniowe, funkcje ciągłe). Dla każdej takiej kategorii 𝐂 możemy zdefiniować tak zwany funktor zapominania U:𝐂𝐒𝐞𝐭 w ten sposób, że każdemu obiektowi X𝐂0 przypisujemy zbiór X=U(X), zaś każdemu morfizmowi f:XY przypisujemy tę samą funkcję f=U(f) niejako zapominając o fakcie, że zachowuje ona zadaną na obiektach 𝐂 strukturę. Dla przykładu funktor zapominania U:𝐆𝐫𝐩𝐒𝐞𝐭 przypisuje każdej grupie G zbiór U(G) elementów grupy G i każdemu homomorfizmowi grup f:GH funkcję f=U(f):U(G)U(H).


Przykład 5.7

Ze strukturą każdej kategorii lokalnie małej 𝐂 związane są tzw. hom-funktory, które odgrywają ogromną rolę w teorii kategorii. Dla każdego obiektu X𝐂0 możemy bowiem zdefiniować operację,
Hom𝐂(,X):𝐂op𝐒𝐞𝐭

zadaną jak następuje:

𝐂0Z  Hom𝐂(Z,X)Set0
𝐂1f:AB  Hom𝐂(f,X):Hom𝐂(B,X)Hom𝐂(A,X)𝐒𝐞𝐭1
p:BX  pf:AX

czyli tak, jak na poniższym diagramie:

Sprawdźmy, że Hom𝐂(,X) jest funktorem. Mamy:

Hom𝐂(1B,X)(p)=p1B=p

z czego wnosimy, że:

Hom𝐂(,X)(1B)=Hom𝐂(1B,X)=1Hom𝐂(B,X)=1Hom𝐂(,X)(B)

Po drugie:

Hom𝐂(fg,X)(p)=pfg=Hom𝐂(g,X)(pf)=(Hom𝐂(g,X)Hom𝐂(f,X))(p)

Dlatego

Hom𝐂(fg,X)=Hom𝐂(g,X)Hom𝐂(f,X)

lub jeśli ktoś woli:

Hom𝐂(,X)(fg)=Hom𝐂(,X)(g)Hom𝐂(,X)(f)
Zwróćmy uwagę, że złożenie gf po aplikacji funktora Hom𝐂(,X) zmienia się w:
Hom𝐂(,X)(g)Hom𝐂(,X)(f)

co jest spowodowane kontrawariantnością funktora.

Definicja 5.8 [Fuktory pełne, wierne]

Funktor T:𝐂𝐃 nazywamy pełnym, jeśli dla każdej pary obiektów C,C𝐂0 i dla każdej strzałki g:T(C)T(C) w 𝐃 istnieje strzałka f:CC w 𝐂 taka, że T(f)=g. Funktor T:𝐂𝐃 nazywamy wiernym (lub zanurzeniem), jeśli dla każdej pary obiektów C,C𝐂0 i każdej pary strzałek f1,f2:CC (strzałki o tej samej dziedzinie i przeciwdziedzinie nazywamy często równoległymi) równość T(f1)=T(f2) implikuje f1=f2.

Kategorie konkretne

Definicja 5.9 [kategoria konkretna]

Każdą kategorię 𝐂, w której istnieje wierny funktor U:𝐂𝐒𝐞𝐭 nazywamy kategorią konkretną.


Oczywiście taki funktor jest funktorem zapominania, co możemy tu wykorzystać do ścisłej definicji pojęcia funktora zapominania (w przeciwieństwie do nieformalnej prezentacji tego pojęcia w Przykładzie 5.6): funktor U:𝐂𝐒𝐞𝐭 nazywamy funktorem zapominania, jeśli jest tym funktorem, który czyni kategorię 𝐂 kategorią konkretną. Przykładem kategorii, która nie jest konkretna, jest kategoria wszystkich zbiorów i relacji 𝐑𝐞𝐥.

Transformacje naturalne

Rozważmy następujący problem: dla dowolnych kategorii 𝐂,𝐃 chcemy skonstruować kategorię oznaczaną Fun(𝐂,𝐃), której obiektami są wszystkie funktory z 𝐂 do 𝐃. Jak moglibyśmy zdefiniować morfizmy tej nowej kategorii (które dalej nazwiemy transformacjami naturalnymi funktorów)?

Otóż, postępujemy podobnie jak przy konstrukcji kategorii 𝐂 (porównaj Zadanie 1.5): transformację naturalną funktora F:𝐂𝐃 w funktor G:𝐂𝐃 zapewni nam rodzina przekształceń (ηA)A𝐂0 taka, że diagram

komutuje dla dowolnych obiektów A,B𝐂0 i strzałki f:AB𝐂1. Nieformalnie mówiąc, aby określić transformację naturalną między dwoma funktorami, musimy zadeklarować jak efekt działania pierwszego z funktorów na każdym obiekcie transformuje się na efekt działania drugiego z funktorów na tym samym obiekcie. To transformowanie musi odbywać się w sposób naturalny, czyli tak, by powyższy diagram komutował.


Definicja 5.10 [transformacja naturalna]

Dla równoległych funktorów F,G:𝐂𝐃 transformacją naturalną η nazywamy przekształcenie przypisujące każdemu obiektowi A strzałkę ηA:F(A)G(A) w 𝐃 takie, że dla dowolnego morfizmu f:AB w 𝐂 diagram

komutuje. Rodzinę strzałek (ηA)A𝐂0 nazywamy komponentami transformacji naturalnej η.

Jeśli każdy komponent transformacji naturalnej η jest izomorfizmem w kategorii 𝐃, wówczas transformację η nazywamy naturalnym izomorfizmem. Ten warunek jest też równoważny temu, że transformacja η:FG traktowana jako strzałka w kategorii funktorów Fun(𝐂,𝐃) jest izomorfizmem - patrz Zadanie 5.1 (o tej sytuacji mówi się też, że F i Gnaturalnie izomorficzne).

Zwróćmy uwagę, że jeśli np. w Zadaniu 4.10 powiedzieliśmy, że w kartezjańsko zamkniętej kategorii 𝐂 z koproduktami istnieje naturalna bijekcja:

A×(B+C)(A×B)+(A×C)

to znaczy to, że funktory: F():=()×(B+C) i G():=(()×B)+(()×C są naturalnie izomorficzne i tak samo dla par funktorów powstałych z pominięcia odpowiednio B i C.


Przykład 5.11 [odwracanie list]

Dla funktora List:𝐒𝐞𝐭𝐌𝐨𝐧 operacja rev:ListList, która mając daną listę, odwraca jej elementy

jest transformacją naturalną. Jeśli A jest zbiorem, to komponent revA:List(A)List(A) jest funkcją odwracającą dowolną listę o elementach z A:

revA([s1,...,sn])=[sn,...,s1]

dla [s1,...,sn]List(A).

Zauważmy, że dla dowolnej funkcji f:AB𝐒𝐞𝐭1 diagram

komutuje, co potwierdza naturalność transformacji rev. Zwróćmy też uwagę, że w żargonie informatycznym komutowanie powyższego diagramu oznacza, że rev jest operacją polimorficzną, czyli, że definicja revA nie zależy od A. Nieformalny wniosek nasuwa się sam: każda funkcja polimorficzna danego języka programowania (funkcyjnego) da się opisać jako pewna transformacja naturalna w odpowiedniej kategorii funktorów.


Definicja 5.12 [kategoria funktorów]

Niech 𝐂 i 𝐃 będą kategoriami. Kategoria funktorów Fun(𝐂,𝐃) jest wyznaczona przez następujące dane:
  • obiekty Fun(𝐂,𝐃)0 to funktory typu 𝐂𝐃,
  • morfizmy Fun(𝐂,𝐃)1 to transformacje naturalne funktorów typu 𝐂𝐃,
  • identyczności: jeśli F:𝐂𝐃 jest funktorem, to identycznością 1F:FF jest transformacja naturalna zdefiniowana jako (1F)A=1F(A) dla A𝐂0,
  • złożenie: dla α:FG,β:GH, gdzie F,G,H są funktorami typu 𝐂𝐃, definiujemy złożenie βα poprzez komponenty jako:
(βα)A=βAαA

dla A𝐂0.


Naturalność βα w powyższej definicji weryfikujemy, jak następuje: dla F:AB𝐂1, H(f)(βα)A)=H(f)βAαA=βBG(f)αA=βBαBF(f) lub po prostu patrząc na komutujący diagram:

Jeśli 𝐂,𝐃 są kategoriami małymi, to kategoria funktorów Fun(𝐂,𝐃) jest eksponentem kategorii 𝐂 i 𝐃 w 𝐂𝐚𝐭, co pokazaliśmy w Zadaniu 4.2. Jeśli jedna z kategorii 𝐂,𝐃 nie jest mała, to Fun(𝐂,𝐃) nie musi być obiektem 𝐂𝐚𝐭. Mimo to umówmy się, że kategorię funktorów Fun(𝐂,𝐃) dla dowolnych kategorii 𝐂,𝐃 będziemy odtąd oznaczać [𝐂,𝐃].

Oto znany z algebry liniowej przykład naturalnego izomorfizmu: przez 𝐕𝐞𝐜𝐭() oznaczamy kategorię przestrzeni wektorowych nad ciałem liczb rzeczywistych wraz z odwzorowaniami liniowymi jako morfizmami. Każda przestrzeń wektorowa V ma przestrzeń dualną V* składającą się z odwzorowań liniowych typu V, tzn. V*=Hom𝐕𝐞𝐜𝐭()(V,) w zapisie kategoryjnym. Co więcej, ()* jest w rzeczywistości hom-funktorem, tj.

()*=Hom𝐕𝐞𝐜𝐭()(,):𝐕𝐞𝐜𝐭op𝐕𝐞𝐜𝐭

Jak się okazuje, dowolna przestrzeń V zanurza się naturalnie w przestrzeń dualną do V*:

ηV:CV**
xevx:V*
evx(f):=fx

Słowo naturalnie, użyte powyżej, jest nieprzypadkowe: zdefiniowana przed chwilą strzałka ηV jest komponentem transformacji naturalnej

η1𝐕𝐞𝐜𝐭()**

której dziedziną jest identyczność na 𝐕𝐞𝐜𝐭. Sprawdźmy, że η jest transformacją naturalną:

(f**ηV)(x)(g)=f**(evx)(g)=(evxf*)(g)=evx(f*(g))=evx(gf)=(gf)(x)=g(f(x))=evf(x)(g)=(ηWf)(x)(g)

Transformacja η jest naturalnym izomorfizmem, gdy V jest skończenie wymiarowa.