
For a drunk person you're getting these equivalences surprisingly right. :)
Ah true, I heard about this Dániel. But then it would be generalized to all classes, or just those three ones?
It would make sense for it to work for any class hierarchy, but honestly I just don't know and I've got an old GHC on my laptop so I can't check. Maybe someone who actually knows will come along and enlighten us. ¯\_(ツ)_/¯
Anyway, trying the same with Applicative and its *sub*class Monad:
pure = return
That's right.
mf <*> ma = let mg = mf >>= \f -> return (return . f) in mg >>= \g -> (ma >>= g)
Is there an easier solution? It's easy enough, but not as trivial as for Applicative => Functor.
I've got (an alpha-equivalent of) the following on a scrap piece of paper: mf <*> mx = mf >>= \f -> mx >>= \x -> return . f $ x It reads nice and fluent.
Why do we write constraints like that:
Functor f => (a -> b) -> f a -> f b or: Functor f => Applicative f
That's a very good question. I agree that it would make a bit more sense if the arrows were reversed. I think it helps to read "Functor f => Applicative f where ..." as "if you've got a Functor then you can have an Applicative if you just implement these functions" as opposed to "if f is a Functor that implies that f is an Applicative" (wrong). Daniel