Saya akan menggunakan deskripsi bahasa-agnostik dari monad seperti ini, pertama menggambarkan monoid:
Sebuah monoid adalah (kira-kira) satu set fungsi yang mengambil beberapa jenis sebagai parameter dan mengembalikan tipe yang sama.
Sebuah monad adalah (kira-kira) satu set fungsi yang mengambil pembungkus tipe sebagai parameter dan mengembalikan tipe pembungkus yang sama.
Perhatikan itu adalah deskripsi, bukan definisi. Jangan ragu untuk menyerang deskripsi itu!
Jadi dalam bahasa OO, monad mengizinkan komposisi operasi seperti:
Flier<Duck> m = new Flier<Duck>(duck).takeOff().flyAround().land()
Perhatikan bahwa monad mendefinisikan dan mengontrol semantik operasi tersebut, bukan kelas yang terkandung.
Secara tradisional, dalam bahasa OO kami akan menggunakan hierarki kelas & warisan untuk menyediakan semantik tersebut. Jadi kami akan memiliki Bird
kelas dengan metode takeOff()
, flyAround()
dan land()
, dan Bebek akan mewarisi itu.
Tapi kemudian kita mendapat masalah dengan burung yang tidak bisa terbang, karena penguin.takeOff()
gagal. Kita harus menggunakan lemparan dan penanganan Exception.
Juga, setelah kami mengatakan bahwa Penguin adalah Bird
, kami mengalami masalah dengan banyak pewarisan, misalnya jika kami juga memiliki hierarki Swimmer
.
Pada dasarnya kami mencoba untuk menempatkan kelas ke dalam kategori (dengan permintaan maaf kepada Teori Kategori guys), dan mendefinisikan semantik berdasarkan kategori daripada di kelas individu. Tetapi, monad tampaknya merupakan mekanisme yang jauh lebih jelas untuk melakukan hal itu daripada hierarki.
Jadi dalam hal ini, kita akan memiliki Flier<T>
monad seperti contoh di atas:
Flier<Duck> m = new Flier<Duck>(duck).takeOff().flyAround().land()
... dan kami tidak akan pernah instantiate a Flier<Penguin>
. Kami bahkan dapat menggunakan pengetikan statis untuk mencegah hal itu terjadi, mungkin dengan antarmuka penanda. Atau pengecekan kemampuan runtime untuk menyelamatkan. Tapi sungguh, seorang programmer seharusnya tidak pernah memasukkan Penguin ke Flier, dalam arti yang sama mereka tidak boleh membagi dengan nol.
Juga, ini lebih umum berlaku. Selebaran tidak harus menjadi Burung. Misalnya Flier<Pterodactyl>
, atau Flier<Squirrel>
, tanpa mengubah semantik dari masing-masing tipe tersebut.
Setelah kita mengklasifikasikan semantik berdasarkan fungsi komposable pada wadah - alih-alih dengan hierarki tipe - itu menyelesaikan masalah lama dengan kelas yang "semacam dilakukan, jenis tidak" cocok dengan hierarki tertentu. Ini juga dengan mudah & jelas memungkinkan beberapa semantik untuk suatu kelas, seperti Flier<Duck>
juga Swimmer<Duck>
. Sepertinya kita telah berjuang dengan ketidakcocokan impedansi dengan mengklasifikasikan perilaku dengan hierarki kelas. Monads menanganinya dengan elegan.
Jadi pertanyaan saya adalah, dengan cara yang sama ketika kita lebih menyukai komposisi daripada warisan, apakah masuk akal juga untuk memilih monad daripada warisan?
(BTW saya tidak yakin apakah ini harus ada di sini atau di Comp Sci, tetapi ini tampaknya lebih seperti masalah pemodelan praktis. Tapi mungkin lebih baik di sana.)