scala - Comprender por qué Zipper es una Comonad
functional-programming (1)
Como esta pregunta aparece regularmente en la parte superior de la lista "sin respuesta", permítanme copiar mi comentario como respuesta aquí; de todos modos, nada más constructivo ha aparecido desde hace un año.
Una List
se puede ver como una comonad (de varias maneras), mientras que una Zipper
se puede convertir como una mónada (también de muchas maneras). La diferencia radica en si te centras conceptualmente en "agregar" datos constructivamente a una máquina de estados (de eso se trata la interfaz Monad
), o si "extraes" el estado "desconstructivamente" (eso es lo que hace Comonad
).
Sin embargo, no es fácil responder a la pregunta, que se expresa como "si este entendimiento tiene sentido". En cierto sentido lo hace, en otro no.
Este es un seguimiento de la answer a mi pregunta anterior.
Supongamos que necesito asignar cada elemento a:A
de la List[A]
a b:B
con la función def f(a:A, leftNeighbors:List[A]): B
y generar List[B]
.
Obviamente no puedo simplemente llamar map
en la lista, pero puedo usar el cremallera de la lista. La cremallera es un cursor para moverse por la lista. Proporciona acceso al elemento actual ( focus
) y sus vecinos.
Ahora puedo reemplazar mi f
con def f''(z:Zipper[A]):B = f(z.focus, z.left)
y pasar esta nueva función f''
al método cobind
de Zipper[A]
.
El cobind
funciona así: llama a f''
con la cremallera, luego mueve la cremallera, llama a f''
con la nueva cremallera "movida", mueve la cremallera de nuevo y así sucesivamente, y así sucesivamente ... hasta que la cremallera llegue a la cremallera fin de la lista.
Finalmente, el cobind
devuelve una nueva cremallera de tipo Zipper[B]
, que puede transformarse en la lista y así se resuelve el problema.
Ahora note la simetría entre cobind[A](f:Zipper[A] => B):Zipper[B]
y bind[A](f:A => List[B]):List[B]
Es por eso que List
es una Monad
y una Zipper
es una Comonad
.
Tiene sentido ?