I looked at past discussion but could not see why any of the answers are actually correct.
Applicative
<*> :: f (a -> b) -> f a -> f b
Monad
(>>=) :: m a -> (a -> m b) -> m b
So if I get it right, the claim is that >>=
cannot be written by only assuming the existence of <*>
Well, let's assume I have <*>
.
And I want to create >>=
.
So I have f a
.
I have f (a -> b)
.
Now when you look at it, f (a -> b)
can be written as (a -> b)
(if something is a function of x, y , z - then it's also a function of x, y).
So from the existence of <*>
we get (a -> b) -> f a -> f b
which again can be written as ((a -> b) -> f a) -> f b
, which can be written as (a -> f b)
.
So we have f a
, we have (a -> f b)
, and we know that <*>
results in f b
, so we get:
f a -> (a -> f b) -> f b
which is a monad.
Actually, in a more intuitive language: when implementing <*>
, I extract (a -> b)
out of f(a -> b)
, I extract a
out of f a
, and then I apply (a -> b)
on a
and get b
which I wrap with f
to finally get f b
.
So I do almost the same to create >>=
. After applying (a -> b)
on a
and getting b
, do one more step and wrap it with f
, so I return f b
, hence I know I have a function (a -> f b)
.
Everyone has already contributed explaining that this is not a fact. Let me prove it to you.
If we genuinely had what you state then we should be able to write a function
Moreover, for any concrete data type we like, call it
F
, we ought to be able to writeLet's worry only about writing
expose_F
since if we can show thatexpose_F
cannot be written for someF
then we have surely shown thatexpose
cannot be written.Let me provide us a test
F
. It will certainly be non-intuitive feeling as I'm intending to use it to break intuition, but I'm happy to confirm all day long that there is nothing funny at all aboutIndeed, it is a
Functor
and an
Applicative
for that mattereven a
Monad
You can verify yourself that all of these typecheck. There's nothing wrong at all about
F
.So what's just right about,
F
? Why did I choose it? WellF
is interesting in that values ofF a
fail to contain anything related at all toa
within them. Often people like to talk about data types (orFunctor
s) as "containers" or "boxes".F
forces us to remember that in a certain sense a box that's 0 inches deep is still a box. [0]So surely we cannot write
There are a number of ways of proving this. The easiest is to appeal to my supposition that you, for instance, believe that there is no
coerce
function. But, if we hadexpose_F
there would be!More specifically, let me introduce another pathological type (which I again assure you is totally fine)
There are zero constructors of
Void
and we like to say therefore thatVoid
has no members. It cannot be made to exist. But we can make one withexpose_F
.In Haskell we're not technically sound enough to execute the above proofs. If you dislike the way I talk about impossibility then you can conjure up whatever types you like with a convenient infinite loop, casual call to
or perhaps an unassuming
undefined
. But these are all on the path of madness.There is no
expose_F
and therefore there is noexpose
.[0] And to be completely clear, thinking of data types as boxes at all is often flawed. Instances of
Functor
tend to be "box-like", but here's another interesting data type which is difficult to think of as a boxunless perhaps you consider
Unbox a
to be a box containing aBool
and a negativea
or something like that. Perhaps anIOU a
.No. It can't. Your intuition is (dangerously) far off at this point. That's like saying a hammer is perfect for driving screws in, since it already works for a nail*. You can't simply drop
f
here, it's part of the type**.Instead, let's get the facts straight. An
Applicative
has three associated functions, countingFunctor
'sfmap
:Here's another fact: you can define bind (
(>>=)
) in terms ofjoin
and vice versa:Those aren't the official definitions of course, since they would never terminate. You have to define
(>>=)
for your type if you want to make it a a monad:First of all,
id :: a -> a
is defined for any type. Second, the mathematical definition of a monad is actually viajoin
. So it's "more"*** legitimate. But most important of all, we can define the monad laws in terms ofjoin
(exercise).If we created
join
viaApplicative
, we could also create bind. If we cannot createjoin
viaApplicative
methods, neither can we derivebind
. Andjoin
's type actually makes it obvious that we cannot derive it fromApplicative
:Join is able to drop one of the
m
layers. Let's check whether it's possible to do the same in the other methods:The answer is no: none of the tools we're given by
Applicative
enables us collapse multiplem
's into a single one. And that's also what is written in the Typeclassopedia right after the cited paragraph in the other question:Note that
join
doesn't make it possible to get rid ofm
completely, that would be a total extraction, and—depending on some other functions—a feature of a comonad. Either way, make sure that you don't let your intuition go astray; trust and use the types.* That comparison is a little bit bad, because you could actually try to dive a screw in with a hammer into a piece of wood. So think of a plastic screw, a rubber hammer and a carbon steel plate you want to drive the nail in. Good luck.
** Well, you can drop it, but then the type changes drastically.
*** Given that
(>>=)
andjoin
are equivalent of power and any(>>=)
using formula can be transformed to one only usingjoin
, they are of course both mathematical sound.