Jika kita membandingkan jenisnya
(<*>) :: Applicative a => a (s -> t) -> a s -> a t
(>>=) :: Monad m => m s -> (s -> m t) -> m t
kami mendapatkan petunjuk tentang apa yang memisahkan kedua konsep tersebut. Bahwa (s -> m t)
dalam tipe (>>=)
menunjukkan bahwa nilai dalam s
dapat menentukan perilaku komputasi dalam m t
. Monads memungkinkan interferensi antara nilai dan lapisan komputasi. The (<*>)
Operator memungkinkan tidak ada gangguan seperti: fungsi dan argumen perhitungan tidak bergantung pada nilai-nilai. Ini benar-benar menggigit. Membandingkan
miffy :: Monad m => m Bool -> m x -> m x -> m x
miffy mb mt mf = do
b <- mb
if b then mt else mf
yang menggunakan hasil dari beberapa efek untuk memutuskan antara dua perhitungan (mis. meluncurkan rudal dan menandatangani gencatan senjata), sedangkan
iffy :: Applicative a => a Bool -> a x -> a x -> a x
iffy ab at af = pure cond <*> ab <*> at <*> af where
cond b t f = if b then t else f
yang menggunakan nilai ab
untuk memilih di antara nilai-nilai dari dua perhitungan at
dan af
, setelah melakukan keduanya, mungkin menghasilkan efek yang tragis.
Versi monadik pada dasarnya bergantung pada kekuatan ekstra (>>=)
untuk memilih penghitungan dari suatu nilai, dan itu bisa jadi penting. Namun, mendukung kekuatan tersebut membuat monad sulit untuk dibuat. Jika kita mencoba membangun 'ikatan ganda'
(>>>>==) :: (Monad m, Monad n) => m (n s) -> (s -> m (n t)) -> m (n t)
mns >>>>== f = mns >>-{-m-} \ ns -> let nmnt = ns >>= (return . f) in ???
kita sampai sejauh ini, tapi sekarang lapisan kita semua campur aduk. Kami memiliki n (m (n t))
, jadi kami harus menyingkirkan bagian luarnya n
. Seperti yang dikatakan Alexandre C, kita bisa melakukannya jika kita punya yang cocok
swap :: n (m t) -> m (n t)
untuk mengubah ke n
dalam dan join
ke yang lain n
.
'Penerapan ganda' yang lebih lemah jauh lebih mudah untuk didefinisikan
(<<**>>) :: (Applicative a, Applicative b) => a (b (s -> t)) -> a (b s) -> a (b t)
abf <<**>> abs = pure (<*>) <*> abf <*> abs
karena tidak ada interferensi antar lapisan.
Sejalan dengan itu, ada baiknya untuk mengenali kapan Anda benar-benar membutuhkan kekuatan ekstra Monad
s, dan kapan Anda bisa lolos dengan struktur komputasi kaku yang Applicative
mendukung.
Perhatikan, ngomong-ngomong, meskipun menyusun monad itu sulit, itu mungkin lebih dari yang Anda butuhkan. Jenis tersebut m (n v)
menunjukkan komputasi dengan m
-efek, kemudian komputasi dengan n
-efek ke v
-nilai, di mana m
-efek selesai sebelum n
-efek dimulai (karena itu diperlukan swap
). Jika Anda hanya ingin m
menyisipkan -efek dengan n
-efek, maka komposisi mungkin terlalu banyak untuk ditanyakan!