Esta é uma continuação da resposta à minha pergunta anterior.
Suponha que eu precise mapear cada item a:A
de List[A]
para b:B
com função def f(a:A, leftNeighbors:List[A]): B
e gerar List[B]
.
Obviamente, não posso apenas chamar map
a lista, mas posso usar o zíper da lista . O zíper é um cursor para mover em uma lista. Ele fornece acesso ao elemento atual ( focus
) e seus vizinhos.
Agora posso substituir o meu f
por def f'(z:Zipper[A]):B = f(z.focus, z.left)
e passar essa nova função f'
para o cobind
método de Zipper[A]
.
As cobind
funciona assim: ele chama a f'
com o zíper, então move o zíper, chamadas f'
com o novo "movidos" zipper, move o zíper de novo e assim por diante, e assim por diante ... até o zíper chega ao fim da lista.
Por fim, o cobind
retorna um novo zíper do tipo Zipper[B]
, que pode ser transformado para a lista e assim o problema é resolvido.
Agora observe a simetria entre cobind[A](f:Zipper[A] => B):Zipper[B]
e bind[A](f:A => List[B]):List[B]
é por isso que List
é um Monad
e Zipper
é um Comonad
.
Isso faz sentido ?