数日前に頭の中で考えてた駄文。
モナドによって性質が大きく違うことからモナドは掴みにくいものだってのはよく言われることだけど、それは各モナドのbindの特色がfmapに入っているかjoinに入っているかにも関連するのかなと思った。
例えば、ListやMaybeだと、joinは皮を剥ぐだけで面白いことは何もしてなくて、fmapにその特色が入っている。
instance Functor [] where
fmap = map
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
逆にStateやIOモナドのfmapは値を普通に関数適用するだけで背後にある状態はまったく触らない。面白いことをやっているのはjoinの方で、状態の変更を外側,内側、と順番に逐次処理する役割を担っている。
join :: (Monad m) => m (m a) -> m a
join x = x >>= id
instance (Monad m) => Monad (StateT s m) where
m >>= k = StateT $ \s -> do
~(a, s') <- runStateT m s
runStateT (k a) s'