Это ответ на ответ на мой предыдущий вопрос.
Предположим, мне нужно сопоставить каждый элемент a:A
от List[A]
до b:B
с помощью функции def f(a:A, leftNeighbors:List[A]): B
и сгенерировать List[B]
.
Очевидно, я не могу просто вызвать map
в списке, но я могу использовать список zipper. Застежка-молния - это курсор для перемещения по списку. Он обеспечивает доступ к текущему элементу (focus
) и его соседям.
Теперь я могу заменить my f
на def f'(z:Zipper[A]):B = f(z.focus, z.left)
и передать эту новую функцию f'
в cobind
метод Zipper[A]
.
cobind
работает следующим образом: он вызывает f'
с помощью молнии, затем перемещает застежку-молнию, вызывает f'
с новой "перемещенной" молнией, снова перемещает застежку-молнию и т.д. и т.д... пока молния не дойдет до конца списка.
Наконец, cobind
возвращает новую застежку-молнию типа Zipper[B]
, которая может быть преобразована в список, и поэтому проблема решена.
Теперь обратите внимание на симметрию между cobind[A](f:Zipper[A] => B):Zipper[B]
и bind[A](f:A => List[B]):List[B]
. Поэтому List
является Monad
и Zipper
является Comonad
.
Имеет ли смысл?