To jest kontynuacja odpowiedzi na moje poprzednie pytanie.
Załóżmy, że trzeba mapować każdy element a:A
od List[A]
do b:B
z funkcji def f(a:A, leftNeighbors:List[A]): B
i generować List[B]
.
Oczywiście nie mogę po prostu zadzwonić map
na listę, ale mogę użyć suwaka listy . Zamek błyskawiczny to kursor do poruszania się po liście. Zapewnia dostęp do bieżącego elementu ( focus
) i jego sąsiadów.
Teraz mogę zastąpić mój f
z def f'(z:Zipper[A]):B = f(z.focus, z.left)
i przekazać tę nową funkcję f'
do cobind
metody Zipper[A]
.
Że cobind
działa tak: to połączenia, które f'
z zamkiem, a następnie przesuwa suwak, rozmowy f'
z nowym „przeniesione” na zamek błyskawiczny, znowu i tak dalej, i tak porusza się na zamek błyskawiczny ... aż osiągnie koniec listy.
Na koniec cobind
zwraca nowy typ zamka błyskawicznego Zipper[B]
, który można przekształcić na listę, dzięki czemu problem został rozwiązany.
Zwróć teraz uwagę na symetrię między cobind[A](f:Zipper[A] => B):Zipper[B]
a bind[A](f:A => List[B]):List[B]
Dlatego List
jest a Monad
i Zipper
jest a Comonad
.
Czy jest sens ?
źródło
Odpowiedzi:
Ponieważ to pytanie regularnie pojawia się na szczycie listy „bez odpowiedzi”, pozwolę sobie tylko skopiować mój komentarz jako odpowiedź - i tak nic bardziej konstruktywnego nie pojawiło się od roku.
ZA
List
może być również postrzegana jako komonada (na wiele sposobów), podczas gdy aZipper
może być rzucana jako monada (również na wiele sposobów). Różnica polega na tym, czy koncepcyjnie koncentrujesz się na „dodawaniu” danych konstruktywnie do automatu stanowego (o to chodzi wMonad
interfejsie), czy na „wydobywaniu” z nich stanu „dekonstrukcyjnie” (to właśnieComonad
robi).Nie jest jednak łatwo odpowiedzieć na pytanie, sformułowane jako „czy to rozumienie ma sens”. W pewnym sensie tak, w innym nie.
źródło