Le risposte qui fanno un ottimo lavoro nel definire sia i monoidi che le monadi, tuttavia, non sembrano ancora rispondere alla domanda:
E su una nota meno importante, è vero e in tal caso potresti dare una spiegazione (si spera che possa essere compresa da qualcuno che non ha molta esperienza con Haskell)?
Il nocciolo della questione che qui manca, è la diversa nozione di "monoide", la cosiddetta categorizzazione più precisamente - quella del monoide in una categoria monoidale. Purtroppo il libro stesso di Mac Lane lo rende molto confuso :
Detto ciò, una monade X
è solo un monoide nella categoria degli endofunctor X
, con il prodotto ×
sostituito dalla composizione degli endofunctor e dall'unità impostata dall'identificatore endofunctor.
Confusione principale
Perché questo è confuso? Perché non definisce ciò che è "monoide nella categoria di endofunctor" di X
. Invece, questa frase suggerisce di prendere un monoide all'interno dell'insieme di tutti gli endofunctor insieme alla composizione di funzione come operazione binaria e il funzione di identità come unità monoida. Che funziona perfettamente e trasforma in un monoide qualsiasi sottoinsieme di endofunctor che contiene il funzione di identità ed è chiuso sotto la composizione del funzione.
Tuttavia questa non è l'interpretazione corretta, che il libro non riesce a chiarire in quella fase. Una Monade f
è un endofunctor fisso , non un sottoinsieme di endofunctor chiusi sotto composizione. Una costruzione comune è usare f
per generare un monoide prendendo l'insieme di tutte k
le composizioni f^k = f(f(...))
di f
se stesso, incluso k=0
quello corrispondente all'identità f^0 = id
. E ora l'insieme S
di tutti questi poteri per tutti k>=0
è davvero un monoide "con prodotto × sostituito dalla composizione di endofunctor e unità impostati dall'identificatore endofunctor".
E ancora:
- Questo monoide
S
può essere definito per qualsiasi funzione f
o anche letteralmente per qualsiasi auto-mappa di X
. È il monoide generato da f
.
- La struttura monoidale
S
data dalla composizione del funzione e dal funzione identità non ha nulla a che fare con l' f
essere o non essere una monade.
E per rendere le cose più confuse, la definizione di "monoide nella categoria monoidale" arriva più avanti nel libro, come si può vedere dal sommario . Eppure comprendere questa nozione è assolutamente fondamentale per comprendere la connessione con le monadi.
(Rigorose) categorie monoidali
Andando al capitolo VII sui monoidi (che viene dopo il capitolo VI sulle monadi), troviamo la definizione della cosiddetta categoria monoidale rigorosa come tripla (B, *, e)
, dove B
è una categoria, *: B x B-> B
un bifunctor (funzione rispetto a ciascun componente con un altro componente fisso ) ed e
è un oggetto unitario B
, soddisfacendo l'associatività e le leggi unitarie:
(a * b) * c = a * (b * c)
a * e = e * a = a
per tutti gli oggetti a,b,c
di B
, e le stesse identità per eventuali morfismi a,b,c
con e
sostituita da id_e
, il morfismo identità e
. È ora istruttivo osservare che nel nostro caso di interesse, dov'è B
la categoria di endofunctor X
con trasformazioni naturali come morfismi, *
composizione del funzione e e
identificatore, tutte queste leggi sono soddisfatte, come può essere verificato direttamente.
Ciò che segue nel libro è la definizione della categoria monoidale "rilassata" , in cui le leggi contengono solo alcune trasformazioni naturali fisse che soddisfano le cosiddette relazioni di coerenza , che tuttavia non è importante per i nostri casi delle categorie di endofunctor.
Monoidi in categorie monoidali
Infine, nella sezione 3 "Monoidi" del capitolo VII, viene data la definizione effettiva:
Un monoide c
in una categoria monoidale (B, *, e)
è un oggetto B
con due frecce (morfismi)
mu: c * c -> c
nu: e -> c
rendendo commutativi 3 diagrammi. Ricordiamo che nel nostro caso si tratta di morfismi nella categoria degli endofunctor, che sono trasformazioni naturali corrispondenti esattamente join
e return
per una monade. La connessione diventa ancora più chiara quando rendiamo la composizione *
più esplicita, sostituendo c * c
con c^2
, dov'è la c
nostra monade.
Infine, si noti che i 3 diagrammi commutativi (nella definizione di un monoide nella categoria monoidale) sono scritti per categorie monoidali generali (non rigide), mentre nel nostro caso tutte le trasformazioni naturali derivanti dalla categoria monoidale sono in realtà identità. Ciò renderà i diagrammi esattamente uguali a quelli nella definizione di monade, completando la corrispondenza.
Conclusione
In sintesi, ogni monade è per definizione un endofunctor, quindi un oggetto nella categoria degli endofunctor, in cui il monadic join
e gli return
operatori soddisfano la definizione di monoid in quella particolare (rigorosa) categoria monoidale . Viceversa, qualsiasi monoide nella categoria monoideale di endofunctor è per definizione una tripla (c, mu, nu)
costituita da un oggetto e due frecce, ad esempio trasformazioni naturali nel nostro caso, che soddisfano le stesse leggi di una monade.
Infine, nota la differenza chiave tra i monoidi (classici) e i monoidi più generali nelle categorie monoidali. Le due frecce mu
e nu
sopra non sono più un'operazione binaria e un'unità in un set. Invece, hai un endofunctor fisso c
. La composizione del funzione *
e il solo dispositivo di identità non forniscono la struttura completa necessaria per la monade, nonostante quell'osservazione confusa nel libro.
Un altro approccio sarebbe quello di confrontare con il monoide standard C
di tutte le auto-mappe di un insieme A
, in cui l'operazione binaria è la composizione, che può essere vista per mappare il prodotto cartesiano standard C x C
in C
. Passando al monoide classificato, stiamo sostituendo il prodotto cartesiano x
con la composizione *
del funzione e l'operazione binaria viene sostituita dalla trasformazione naturale mu
da
c * c
a c
, ovvero una raccolta di join
operatori
join: c(c(T))->c(T)
per ogni oggetto T
(digitare in programmazione). E gli elementi di identità nei monoidi classici, che possono essere identificati con immagini di mappe da un set di un punto fisso, vengono sostituiti con la raccolta degli return
operatori
return: T->c(T)
Ma ora non ci sono più prodotti cartesiani, quindi nessuna coppia di elementi e quindi nessuna operazione binaria.