Questo è un seguito alla risposta alla mia domanda precedente.
Supponiamo di dover mappare ogni elemento a:A
di List[A]
a b:B
con la funzione def f(a:A, leftNeighbors:List[A]): B
e generare List[B]
.
Ovviamente non posso semplicemente chiamare map
sulla lista ma posso usare la cerniera della lista . La cerniera è un cursore per spostarsi in un elenco. Fornisce accesso all'elemento corrente ( focus
) e ai suoi vicini.
Ora posso sostituire my f
con def f'(z:Zipper[A]):B = f(z.focus, z.left)
e passare questa nuova funzione f'
al cobind
metodo di Zipper[A]
.
Le cobind
opere come questa: si chiama che f'
con la cerniera, poi si sposta la cerniera, le chiamate f'
con la nuova "mosso" cerniera, muove la cerniera di nuovo e così via, e così via ... fino a quando la cerniera raggiunge la fine della lista.
Infine, cobind
restituisce una nuova cerniera di tipo Zipper[B]
, che può essere trasformata in lista e così 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
è a Monad
ed Zipper
è a Comonad
.
Ha senso ?