Masalah pemrograman apa yang dipecahkan Monads? [Tutup]

14

Saya telah membaca banyak posting yang menjelaskan apa itu monad, bagaimana unitdanbind 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?

Dummy Me
sumber
3
Programnya besar dan kompleks. Kita perlu cara untuk menyusunnya. Ada banyak cara. Monad adalah satu. Panah adalah satu. Functors adalah satu. Objek, Kelas, Fungsi, Metode, Modul, Ciri, Mixin, Paket, dan lainnya, Benar-benar tidak jelas apa pertanyaan spesifik Anda. Apakah Anda bertanya mengapa kami perlu menyusun program?
Jörg W Mittag
1
@ JörgWMittag: Saya TIDAK bertanya mengapa kita perlu menyusun program. Jelas masalah besar terpecah menjadi yang lebih kecil yang bisa Anda pecahkan dan kemudian gabungkan untuk mendapatkan solusi untuk yang besar. Saya bertanya masalah apa yang dipecahkan Monads. Itu saja? Kode penataan? Apakah hanya itu yang diributkan? Misalnya, di Haskell ini adalah bagaimana Anda melakukan I / O. Di sana, monad adalah permainan pura-pura bertindak seperti sesuatu yang murni padahal sebenarnya tidak. Pertanyaan saya ada di judul, saya tidak tahu bagaimana menyatakannya dengan cara yang lebih jelas.
Dummy Me
2
Mengapa monad
Robert Harvey
1
@RobertHarvey: Saya juga menemukan dua tautan pertama yang Anda tambahkan tetapi seperti pada jawaban dari pos-pos itu dan yang lain, tanggapan langsung ke Maybe, State dan IO monads, dengan cepat beralih ke contoh atau kode, dan diakhiri dengan "ada banyak masalah yang dapat dipecahkan menggunakan Monads ". Apa jenis masalah lainnya? Saya mencari jawaban tingkat yang lebih tinggi bahwa alih-alih mengulangi contoh yang sama malah menuju akar masalah (apa pun itu) dan menjelaskan bagaimana Monads memecahkannya dan mengapa itu pilihan terbaik, daripada menggunakan sesuatu yang lain. Terima kasih banyak atas umpan baliknya.
Dummy Me

Jawaban:

10

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.

Karl Bielefeldt
sumber
2
Saya benar-benar akan mengatakan bahwa hal yang paling mungkin dilakukan haskell monads adalah cara mudah untuk memiliki efek IO yang benar-benar bekerja seperti yang Anda harapkan. Saya pikir siapa pun yang bertanya apa yang diberikan monad kepada kita harus mencoba Miranda . Miranda adalah bahasa yang dirancang untuk diganti Haskell, dan seharusnya sangat mudah dipelajari bagi siapa pun yang memiliki pengalaman Haskell. Perbedaan utama adalah bahwa ia tidak memiliki IO monadik, yang membuat bahasa lebih sulit untuk digunakan daripada Haskell untuk proyek non-sepele.
Jules
Ya, IOadalah 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.
Karl Bielefeldt
1
@ Jules: Atau lihat sejarah Haskell. Sebelum Monads, para desainer Haskell bereksperimen dengan Lazy Streams dan Continuations sebagai dasar untuk I / O, dan keduanya sulit digunakan.
Jörg W Mittag
5

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.

JacquesB
sumber
2

Satu hal yang membuatnya membingungkan adalah bahwa fungsi "populer" suka binddan<*> 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 di fmana 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 menggunakan fmapatau 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 dari Functordan Monoidal, Dan juga Unit, yang hanya menambahkan bahwa Anda benar-benar dapat menempatkan nilai "di dalam" konteks Anda unit.

Anda dapat menulis fungsi yang sangat umum dengan hanya menyatakan tiga hal ini tentang konteks tempat Anda bekerja.

Monadhanyalah 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 dapat pairmereka, 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 tipe FilePath -> IO (IO a). Bagaimana kita bisa menghilangkan susunan itu untuk mendapatkan fungsi yang dapat dieksekusi IO a? Di situlah Monads joinmasuk, memungkinkan kita untuk menggabungkan dua konteks bertumpuk dari jenis yang sama. Hal yang sama berlaku untuk parser, Mungkin dll. Dan bindhanya 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.

Marlin
sumber
1

Monads memungkinkan Anda mengekspresikan berbagai perhitungan yang tidak murni serta menyederhanakan kode

  • perhitungan stateful (dapatkan / atur keadaan melalui monad)
  • I / O (logging, UI, file atau hanya menghasilkan / menggunakan daftar X)
  • Juga, aliran kontrol "non-linear" (yaitu pengecualian, mungkin, dll.)

Dan, yang penting tanpa kompromi dengan konstruksi bahasa murni dan mengeluarkan bahasa yang lebih bersih darinya

Macke
sumber
2
Benar - tetapi itu hanya sebagian dari tujuan penggunaan monad. Daftar pemahaman atau Maybetidak terkait dengan sesuatu yang eksternal.
JacquesB
Akan sangat membantu jika downvoters menjelaskan mengapa mereka melakukannya. Saya tidak melihat ada yang salah dengan jawaban ini.
Jules
@ JacquesB mereka, bagaimanapun, stateful.
Jules
1
Tipe Dunia, Tipe Keunikan, Tipe Linear memungkinkan Anda melakukan itu juga.
Jörg W Mittag
@Jules Daftar sebagai monad nondeterminisme stateful? Bisakah Anda mengklarifikasi apa definisi "stateful" Anda?
Jack