Capire perché Zipper è una Comonade
-
21-12-2019 - |
Domanda
Questo è il seguito di risposta alla mia domanda precedente.
Supponiamo di dover mappare ciascun elemento a:A
Di List[A]
A b:B
con funzione def f(a:A, leftNeighbors:List[A]): B
e generare List[B]
.
Ovviamente non posso semplicemente chiamare map
nell'elenco ma posso usare l'elenco cerniera.La cerniera è un cursore per spostarsi all'interno di un elenco.Fornisce l'accesso all'elemento corrente (focus
) e i suoi vicini.
Ora posso sostituire il mio f
con def f'(z:Zipper[A]):B = f(z.focus, z.left)
e passare questa nuova funzione f'
A cobind
metodo di Zipper[A]
.
IL cobind
funziona così:si chiama così f'
con la cerniera, poi sposta la cerniera, chiamaf'
con il nuovo cerniera "spostata", sposta nuovamente la cerniera e così via, e così via...finché la cerniera non raggiunge la fine dell'elenco.
Infine, il cobind
restituisce un nuovo tipo di zip Zipper[B]
, che può essere trasformato in elenco e quindi il problema è risolto.
Ora nota la simmetria tra cobind[A](f:Zipper[A] => B):Zipper[B]
E bind[A](f:A => List[B]):List[B]
Ecco perché List
è un Monad
E Zipper
è un Comonad
.
Ha senso ?
Soluzione
Dato che questa domanda appare regolarmente in cima all'elenco delle "senza risposta", lasciami semplicemente copiare il mio commento come risposta qui: comunque non è apparso nulla di considerevolmente più costruttivo da un anno fa.
UN List
può essere visto anche come una comonade (in più modi), mentre a Zipper
può essere lanciato come una monade (anche in molti modi).La differenza sta nel fatto se sei concettualmente concentrato sull'"aggiungere" dati in modo costruttivo a una macchina a stati (questo è ciò che Monad
riguarda l'interfaccia) o "estrarre" lo stato da esso "in modo decostruttivo" (questo è ciò di cui si occupa il file Comonad
fa).
Non è però facile rispondere alla domanda “questa interpretazione ha senso?”.In un certo senso lo fa, in un altro no.