I understand the reasoning behind <$>
's type signature, as it's just an infix version of fmap
, but comparing it to >>=
's type signature it makes a lot less sense to me.
Let's first establish what I mean by that.
(>>=) :: Monad m => m a -> (a -> m b) -> m b
(<*>) :: Applicative f => f (a -> b) -> f a -> f b
(<$>) :: Functor f => (a -> b) -> f a -> f b
Looking at the type signatures we can see that >>=
takes a value on the left, and a function on the right, which makes a lot of sense if you consider its chaining property: foo >>= bar >>= baz
Which leads me to wonder, why don't <*>
and <$>
do that too? you can't write foo <*> bar <*> baz
because it would require the output of foo <*> bar
to be a function, not a value.
I know that <**>
and =<<
exist that both flip the order of the parameters, allowing me to do something like:
Just 4 <**> pure (+3) <**> pure (*2) >>= (\x -> Just (x-3))
Which could have been beautifully reduced to:
Just 4 <$$> (+3) <$$> (*2) >>= (\x -> Just (x-3))
If <$$>
had existed, or if the parameter order of <$>
and <*>
had been reversed.
Another thing that makes me wonder why the difference exists, is that it makes it harder for newcomers to get used to and/or remember whether it's the function, or the value that comes first, without having to look it up.
So why is it that in the cases of <*>
and <$>
it's fn op val
but with >>=
it's val op fn
?