Monade și comonade
O noțiune care este de neevitat în programarea funcțională este aceea de monadă. În principiu, o monadă este un functor care poate condensa mai multe aplicări ale sale într-o singură aplicare într-un mod monoidal. Cu alte cuvinte, o monadă este un monoid în categoria endofunctorilor din care aparține (ignorăm momentan posibilitatea de a nu avea categoria de endofunctori dacă există probleme de dimensionare). Bineînțeles, noțiunea duală este cea de comonadă, un comonoid în categoria endofunctorilor din care aparține. O comonadă face exact inversul fată de o monadă, desfășoară aplicarea sa în mai multe aplicări.
Deși comonadele nu sunt atăt de discutate cum sunt monadele, aceste sunt extrem de utile și interesante. Vom vedea în cele ce urmează cum anume monadele și comonadele ne ajută.
Monade
Fie o categorie. O monadă este un triplet unde este un endofunctor, și sunt două transformări naturale, numite unitatea, respectiv multiplicarea monadei, cu proprietatea că următoarele diagrame comută:
Diagramele pot fi condensate în formulele:
Practic, unitatea monadei duce obiecte în aplicări ale monadei iar multiplicarea condensează aplicări multiple astfel încât indiferent cum aplicăm transformările naturale obținem aceiași singură aplicare a monadei. Aceste două transformări naturale sunt cunoscute ca funcțiile return :: a -> T a și join :: T (T a) -> T a din Haskell dar de obicei monadele sunt definite ca operațiile return și bind :: T a -> (a -> T b) -> T b. Operația de bind este practic join aplicat după fmap. Alt nume pentru bind este flatMap pentru că asta și face, aplică o mapare și aplatizează (flattens) tipul de date, join este doar o operație de aplatizare și se mai numeste flatten. Utilitate monadelor constă în faptul că unitatea ne permite să înglobăm date într-un functor iar multiplicarea agregă datele din mai multe aplicări sau contexte într-un singur context ca să lucram mai ușor cu instanța functorului.
Comonade
Fie o categorie. O comonadă este un triplet unde este un endofunctor, și sunt două transformări naturale, numite counitatea, respectiv comultiplicarea comonadei, cu proprietatea că următoarele diagrame comută:
Diagramele pot fi condensate în formulele:
Counitatea și comultiplicarea acționează în sensul invers ca la unitatea și multiplicarea monadei, acestea mai sunt cunoscute în limbajele de programare ca extract :: G a -> a și duplicate :: G a -> G (G a) având și dualul lui bind ca cobind :: (a -> G b) -> G a -> G b. Ambele asigură că indiferent cum le aplicăm obținem aceleași tipuri de date imbricate. Comonadele sunt foarte utile pentru că counitatea poate extrage obiectul din interiorul aplicării functorului, lucru care lipsește la monade, adică la nevoie putem accesa direct datele dintr-o comonadă dacă dorim. Comultiplicarea este de asemena foarte utilă pentru că ne permite să duplicăm date și să le refolosim în contexte noi.
Legătura cu adjuncții
Un lucru important legat de (co)monade este faptul că acestea apar mereu dintr-o pereche de functori adjuncți. Dacă avem doi functori adjuncți , și atunci există o monadă și o comondă .
- monada este compusul functorilor , unitatea monadei este unitatea adjuncției iar multiplicarea este data de counitatea adjuncției
- comonada este compusul functorilor , counitatea comonadei este counitatea adjuncției iar comultiplicarea este data de unitatea adjuncției
Canonic exista două categorii prin care putem defini adjuncții care produc monade, anume categoria Kleisli a unei monade și categoria Eilenberg-Moore sau categoria algebrelor pentru o monadă.
Categoria Kleisli
Fie o categorie și cu o monadă . Categoria Kleisli a acestei monade este cu:
Cu alte cuvinte, obiectele sunt aceleași dar devin . Astfel avem:
- , ,
Putem crea o pereche de functori adjuncți în felul următor:
- L mapează fiecare obiect din la același obiect din , și orice morfism la
- R mapează fiecare obiect din la și orice morfism la
Se poate vedea ușor că acești doi functori sunt adjuncți și produc monada:
- ,
- ,
- unitatea adjuncției există deja și este unitatea monadei
Invers, obținem o comonadă :
- ,
- ,