Saya telah membaca banyak posting yang menjelaskan apa itu monad, bagaimana unit
danbind
bekerja, beberapa di antaranya terjun langsung ke teori kategori yang sangat abstrak (setidaknya bagi saya) yang membuat mata berdarah, beberapa mengabaikan itu sama sekali dan menyentuh analogi aneh dari burrito, kotak dan apa yang tidak.
Setelah beberapa minggu belajar dan banyak neuron goreng, (saya pikir) saya mengerti bagaimana Monads bekerja. Tetapi masih ada satu hal yang luput dari pemahaman saya, sesuatu yang benar-benar disentuh beberapa posting (kecuali untuk IO dan status):
MENGAPA?
Mengapa Monads penting? Mengapa mereka begitu penting? Apa masalah yang mereka pecahkan? Bisakah masalah itu hanya diselesaikan dengan Monads atau ada beberapa cara lain?
sumber
Jawaban:
Kamu tidak perlu monad untuk menyelesaikan apa pun. Mereka hanya membuat hal-hal tertentu lebih sederhana. Banyak orang yang terlalu abstrak dan teoretis ketika menjelaskan monad. Sebagian besar, monad adalah pola yang muncul berulang kali dalam pemrograman. Dengan mengenali pola itu, kita dapat menyederhanakan kode kita dan menghindari penerapan kembali fungsi-fungsi tertentu.
Bagi Haskell, dari sudut pandang konkret, hal yang paling terlihat memungkinkan monad adalah notasi . Daftar pemahaman dalam bahasa Haskell dan lainnya juga mengambil keuntungan besar dari monad. Anda juga dapat membuat perpustakaan seperti Control.Monad .
Ini semua memberikan penyederhanaan yang berguna, dan setelah Anda menerapkannya untuk satu monad, Anda secara otomatis mendapatkannya untuk semua monad. Ini adalah salah satu alasan utama mengapa penggunaan kembali kode jauh lebih mudah untuk pemrograman fungsional daripada paradigma lain.
sumber
IO
adalah monad Haskell yang paling menonjol , tetapi saya tidak mencantumkan contoh monad individu. Saya membuat daftar contoh abstraksi menyeluruh yang mereka aktifkan. Saya mencoba memahami mengapa, misalnya, orang pertama yang berpikir untuk menggunakan monad untuk IO akan berpikir itu adalah ide yang baik secara umum.Lebih mudah dipahami jika Anda melihat monad tertentu dan melihat masalah apa yang mereka pecahkan. Misalnya, di Haskell:
IO: Memungkinkan IO diwakili dalam sistem tipe, sehingga Anda dapat membersihkan fungsi murni terpisah dari fungsi yang menjalankan IO.
Daftar: Memungkinkan Anda melakukan pemahaman daftar dan perhitungan nodeterministik.
Mungkin: Alternatif yang lebih baik dari nol, dan mendukung sesuatu yang sebanding dengan operator penggabungan nol C #.
Parsec: DSL yang nyaman untuk menulis parser.
Jadi mudah (saya harap) melihat alasan untuk masing-masing monad, karena semuanya sangat berguna. Tetapi masalah yang mereka selesaikan juga sangat berbeda dan di muka mereka tampaknya tidak memiliki banyak kesamaan, kecuali mereka semua terkait dengan beberapa logika untuk operasi rantai. Monads berguna karena memungkinkan Anda membangun berbagai alat.
Bisakah contoh di atas diimplementasikan tanpa monad? Tentu saja mereka dapat diimplementasikan secara ad-hoc, tetapi memiliki monad yang dibangun ke dalam bahasa memungkinkan dukungan langauge langsung seperti
do
-notasi yang bekerja dengan semua monad.sumber
Satu hal yang membuatnya membingungkan adalah bahwa fungsi "populer" suka
bind
dan<*>
berorientasi praksis. Tetapi untuk memahami konsep-konsep itu lebih mudah untuk melihat fungsi-fungsi lain terlebih dahulu. Perlu juga dicatat bahwa monad menonjol karena mereka sedikit overhyped dibandingkan dengan konsep-konsep terhubung lainnya. Jadi saya akan mulai dengan functors saja.Functors menawarkan fungsi (dalam notasi Haskell)
fmap :: (Functor f) => (a -> b) -> f a -> f b
. Dengan kata lain Anda memiliki konteks dif
mana Anda dapat mengangkat suatu fungsi. Seperti yang dapat Anda bayangkan, hampir semuanya adalah functor. Daftar, Mungkin, Either, fungsi, I / O, tuple, parser ... Masing-masing mewakili konteks di mana nilai dapat muncul. Jadi, Anda dapat menulis fungsi yang sangat serbaguna yang bekerja di hampir semua konteks dengan menggunakanfmap
atau varian inline-nya<$>
.Apa hal lain yang ingin Anda lakukan dengan konteks? Anda mungkin ingin menggabungkan dua konteks. Jadi, Anda mungkin ingin mendapatkan generalisasi dari
zip :: [a] -> [b] -> [(a,b)]
contohnya seperti ini:pair :: (Monoidal f) => f a -> f b -> f (a,b)
.Tetapi karena ini bahkan lebih berguna dalam praktiknya, perpustakaan Haskell malah menawarkan
Applicative
, yang merupakan kombinasi dariFunctor
danMonoidal
, Dan jugaUnit
, yang hanya menambahkan bahwa Anda benar-benar dapat menempatkan nilai "di dalam" konteks Andaunit
.Anda dapat menulis fungsi yang sangat umum dengan hanya menyatakan tiga hal ini tentang konteks tempat Anda bekerja.
Monad
hanyalah hal lain yang bisa Anda sebutkan di atas itu. Apa yang tidak saya sebutkan sebelumnya adalah bahwa Anda sudah memiliki dua cara untuk menggabungkan dua konteks: Anda tidak hanya dapatpair
mereka, tetapi Anda juga dapat menumpuknya, misalnya Anda dapat memiliki daftar daftar. Dalam konteks I / O, contoh akan menjadi tindakan I / O yang dapat membaca tindakan I / O lainnya dari file, sehingga Anda akan memiliki tipeFilePath -> IO (IO a)
. Bagaimana kita bisa menghilangkan susunan itu untuk mendapatkan fungsi yang dapat dieksekusiIO a
? Di situlahMonad
sjoin
masuk, memungkinkan kita untuk menggabungkan dua konteks bertumpuk dari jenis yang sama. Hal yang sama berlaku untuk parser, Mungkin dll. Danbind
hanya cara yang lebih praktis untuk digunakanjoin
Jadi konteks monadik hanya menawarkan empat hal dan dapat digunakan dengan hampir semua mesin yang dikembangkan untuk I / O, untuk parser, untuk kegagalan dll.
sumber
Monads memungkinkan Anda mengekspresikan berbagai perhitungan yang tidak murni serta menyederhanakan kode
Dan, yang penting tanpa kompromi dengan konstruksi bahasa murni dan mengeluarkan bahasa yang lebih bersih darinya
sumber
Maybe
tidak terkait dengan sesuatu yang eksternal.