Sari la conținutul principal

Functor

Programatorii sunt obișnuiți cu conceptul de functor și pot recunoaște tipuri generice, cum sunt listele, ca functori în limbajele orientate pe obiecte, deoarece de obicei au o metodă map/fmap/select care pot transforma o listă de tip List<int> într-o listă List<string> printr-o funcție f:intstringf : int \rightarrow string.

Adevărul este că conceptul de functor din matematică și cel din programare reprezintă același concept din perspective diferite. Corespondența nu este întotdeauna intuitivă și evidentă, iar în continuare vom arăta de ce.

Definiție: Functor

Un functor FF de la o categorie CC la alta DD, notat F:CDF : C \rightarrow D, este o mapare care trimite xOb(C)\forall x \in Ob(C) într-un obiect F(x)Ob(D)F(x) \in Ob(D) și care trimite fHom(C)\forall f \in Hom(C) într-un morfism F(f)Hom(D)F(f) \in Hom(D), astfel încât:

  • FF conservă compoziția: F(hg)=F(h)F(g)F(h \circ g) = F(h) \circ F(g)
  • FF conservă identitatea: F(idx)=idF(x)F(id_{x}) = id_{F(x)}

Practic, un functor este un homomorfism (mapare care conservă structura) între două categorii.

Legătura cu programarea

Revenind la corespondența între programare și matematică, putem evidenția legătura considerând următorul exemplu. Să presupunem că, în cadrul unui program, avem trei tipuri de date: int, bool și string, cu următoarele funcții între ele: toString:intstringtoString : int \rightarrow string și isOdd:intboolisOdd : int \rightarrow bool. Să presupunem că tipurile noastre de bază reprezintă o categorie, cu tipurile fiind obiecte, iar funcțiile morfisme. Dacă am introduce un functor numit ListList ca un tip generic care are o funcție map:List a(ab)List bmap : List\ a \rightarrow (a \rightarrow b) \rightarrow List\ b, atunci tuplul (List,map)(List, map) reprezintă functorul conform definiției date, ca cele două mapări pe obiecte, respectiv morfisme.

notă

Acesta este doar un exemplu care să ilustreze conceptual ideea de functor pentru un programator. În realitate, formalizarea sistemelor de tipuri sub forma de categorii este mult mai complexă.

Ce putem observa aici este că functorul nu conservă structura internă a unui tip de date - aceasta este irelevantă într-un context funcțional - ci conservă structura relațiilor între tipurile de date. De asemenea, pentru alte tipuri generice cu diferite proprietăți, trebuie incluse mai multe obiecte și morfisme în categoria destinație pentru functor. Categoria destinație poate include alte obiecte și morfisme la care nu se mapează din categoria sursă.

Compunere

La fel ca morfismele și functorii pot fi compuși, dacă avem functorii F:CDF : C \rightarrow D și G:DEG : D \rightarrow E atunci va exista un functor GF:CEG \circ F : C \rightarrow E care aplicat pe xOb(c)x \in Ob(c) și fHom(C)f \in Hom(C) duc în G(F(x))Ob(E)G(F(x)) \in Ob(E) respectiv G(F(f))Hom(E)G(F(f)) \in Hom(E).

Functorul identitate

Un caz special de (endo)functor este functorul identitate IdC:CCId_C : C \rightarrow C (endofunctorii sunt functori cu sursa și destinația aceiași categorie) care satisface proprietățile:

IdC(x)=x, xOb(C)Id_C(x) = x,\ \forall x \in Ob(C) IdC(f)=f, fHom(C)Id_C(f) = f,\ \forall f \in Hom(C)

Astfel acest functor pentru conpunerea oricare functori F:XCF : X \rightarrow C, G:CXG : C \rightarrow X satisface relațiile:

IdCF=FId_C \circ F = F GIdC=GG \circ Id_C = G

Resurse