Ini merupakan tindak lanjut dari jawaban atas pertanyaan saya sebelumnya.
Misalkan saya perlu untuk memetakan setiap item a:A
dari List[A]
untuk b:B
dengan fungsi def f(a:A, leftNeighbors:List[A]): B
dan menghasilkan List[B]
.
Jelas saya tidak bisa begitu saja memanggil map
daftar tetapi saya bisa menggunakan daftar ritsleting . Ritsleting adalah kursor untuk bergerak di sekitar daftar. Ini menyediakan akses ke elemen saat ini ( focus
) dan tetangganya.
Sekarang saya bisa mengganti f
dengan saya def f'(z:Zipper[A]):B = f(z.focus, z.left)
dan meneruskan fungsi baru ini f'
ke cobind
metode Zipper[A]
.
Cara cobind
kerjanya seperti ini: ia menyebutnya f'
dengan ritsleting, lalu memindahkan ritsleting, memanggil f'
dengan ritsleting baru yang "dipindahkan", memindahkan ritsleting lagi dan seterusnya, dan seterusnya ... hingga ritsleting mencapai akhir daftar.
Akhirnya, cobind
mengembalikan jenis ritsleting baru Zipper[B]
, yang dapat diubah ke daftar dan masalah terpecahkan.
Sekarang perhatikan simetri antara cobind[A](f:Zipper[A] => B):Zipper[B]
dan bind[A](f:A => List[B]):List[B]
Itu sebabnya List
adalah a Monad
dan Zipper
adalah a Comonad
.
Apakah masuk akal ?
sumber
Jawaban:
Karena pertanyaan ini sering muncul di bagian atas daftar "tak terjawab", izinkan saya menyalin komentar saya sebagai jawaban di sini - tidak ada yang lebih konstruktif yang muncul sejak setahun yang lalu.
A
List
juga dapat dilihat sebagai comonad (dalam berbagai cara), sedangkan aZipper
dapat ditampilkan sebagai monad (juga dalam banyak cara). Perbedaannya adalah apakah Anda secara konseptual berfokus pada "menambahkan" data secara konstruktif ke mesin status (itulahMonad
intinya), atau "mengekstrak" status darinya "secara dekonstruktif" (itulah yangComonad
dilakukannya).Tidaklah mudah untuk menjawab pertanyaan yang dinyatakan sebagai "apakah pemahaman ini masuk akal". Dalam beberapa hal memang demikian, di sisi lain tidak.
sumber