Di recente ho rispolverato le mie conoscenze su come funzionano le Monadi. Sono stato anche introdotto al concetto di "Comonad" , che è descritto come il doppio inverso di una monade . Tuttavia, sono impossibile avvolgerci la testa.
Per capire Monads, ho fatto la mia analogia per me stesso:
Le monadi possono essere viste come "un progetto per costruire nastri trasportatori di espressioni".
Per definire una nuova Monade (un nuovo tipo di sistema di nastri trasportatori) è necessario definire:
- Un modo per mettere qualcosa su un nastro trasportatore, ad esempio "avviare" un nastro trasportatore. (Conosciuto come
unit
oreturn
)- Un modo per collegare una macchina (un'espressione) che farà parte di un nastro trasportatore a un nastro trasportatore. (Conosciuto come
join
obind
o>>=
).(Esiste una terza operazione che prende l'attuale nastro trasportatore, ne getta via il contenuto e avvia un nuovo nastro trasportatore noto come
>>
, ma viene usato molto raramente.)Affinché le macchine e i nastri trasportatori funzionino correttamente insieme, è necessario assicurarsi che:
- Se si mette qualcosa su un nastro trasportatore e lo si passa attraverso una macchina, l'output dovrebbe essere lo stesso di quando lo si passa attraverso la macchina manualmente. (Identità sinistra)
- Se vuoi mettere un nastro trasportatore tra un nastro trasportatore già esistente, non dovresti finire con un nastro trasportatore che ha un nastro trasportatore in cima, ma piuttosto un singolo nastro trasportatore più lungo. (Identità corretta)
- Non dovrebbe importare per l'uscita se si utilizza manualmente la macchina A, quindi si passa il risultato attraverso il BC collegato al trasportatore, o se si utilizza AB collegato al trasportatore e quindi si passa il risultato manualmente attraverso C. In altre parole: ((a >> = b) >> = c) dovrebbe essere uguale a (a >> = (b >> = c)) (associatività)
Il nastro trasportatore più semplice sarebbe quello che prende semplicemente l'input e continua sempre con l'espressione successiva. Questa è una "pipeline".
Un'altra possibilità è quella di lasciarlo passare attraverso la macchina successiva solo se viene soddisfatta una condizione per il valore. Ciò significa che se in alcune delle espressioni intermedie, il valore cambia in qualcosa che non è più consentito, il resto delle espressioni verrà saltato. Questo è ciò che fa la monade "Forse" a Haskell.
Puoi anche fare altre fantasiose regole condizionali di copia / modifica sui valori prima o dopo averli passati a una macchina. Un esempio: parser (qui, se un'espressione restituisce un risultato 'fallito', il valore precedente all'espressione viene usato come output).
Naturalmente l'analogia non è perfetta, ma spero che dia una buona rappresentazione di come funzionano le monadi.
Tuttavia, ho molti problemi a capovolgere questa analogia per capire Comonads. So dalle piccole quantità di informazioni che ho trovato su Internet che un Comonad definisce:
extract
, che è una specie del contrario direturn
, cioè prende un valore da una Comonad.duplicate
, che è una sorta di inverso dijoin
, cioè crea due Comonadi da un singolo.
Ma come si può creare un'istanza di Comonad se siamo in grado di estrarre da loro o duplicarli? E come possono essere effettivamente utilizzati? Ho visto questo fantastico progetto e ne ho parlato (di cui ho purtroppo capito molto poco), ma non sono sicuro di quale parte della funzionalità sia fornita esattamente da un Comonad.
Cos'è una Comonad? A cosa servono? Come possono essere usati? Sono commestibili?
IO
monade è il sistema di runtime Haskell, che invoca main
. C'è anche unsafePerformIO
, ovviamente. Se vuoi pensare alla Maybe
monade come se avesse una "macchina all'estremità del nastro trasportatore" che puoi usare maybe
.
cobind
applicazioni, ci deve essere una funzione che fa qualcosa di utile con la rappresentazione interna del tuo comonad.