The related Question is
In the first question:
What is so special about Monads?
A monad is a mathematical structure which is heavily used in (pure) functional programming, basically Haskell. However, there are many other mathematical structures available, like for example applicative functors, strong monads, or monoids. Some have more specific, some are more generic. Yet, monads are much more popular. Why is that?
The comment to reply the question:
As far as I recall, monads were popularised by Wadler, and at the time the idea of doing IO without tedious CPS and parsing without explicit state passing were huge selling points; it was a hugely exciting time. A.F.A.I.R., Haskell didn't do constructor classes, but Gofer (father of Hugs) did. Wadler proposed overloading list comprehension for monads, so the do notation came later. Once IO was monadic, monads became a big deal for beginners, cementing them as a major thing to grok. Applicatives are much nicer when you can, and Arrows more general, but they came later, and IO sells monads hard. – AndrewC May 9 '13 at 1:34
The answer by @Conal is:
I suspect that the disproportionately large attention given to this one particular type class (
Monad
) over the many others is mainly a historical fluke. People often associateIO
withMonad
, although the two are independently useful ideas (as are list reversal and bananas). BecauseIO
is magical (having an implementation but no denotation) andMonad
is often associated withIO
, it's easy to fall into magical thinking aboutMonad
.
First of all, I agree with them, and I think the usefulness of Monads mostly arises from Functors that we can embed many functions within the structure, and Monads is a little expansion for robustness of function composition by join
: M(M(X)) -> M(X)
to avoid the nested type.
In the 2nd Question:
do we have to use monadic functions a -> m b?
so many tutorials around the web still insist to use a monadic functions since that is the Kleisli triple and the monad-laws.
and many answers like
I like to think of such an m as meaning "plan-to-get", where "plans" involve some sort of additional interaction beyond pure computation.
or
In situations where
Monad
isn't necessary, it is often simpler to useApplicative
,Functor
, or just basic pure functions. In these cases, these things should be (and generally are) used in place of aMonad
. For example:
ws <- getLine >>= return . words -- Monad
ws <- words <$> getLine -- Functor (much nicer)
To be clear: If it's possible without a monad, and it's simpler and more readable without a monad, then you should do it without a monad! If a monad makes the code more complex or confusing than it needs to be, don't use a monad! Haskell has monads for the sole purpose of making certain complex computations simpler, easier to read, and easier to reason about. If that's not happening, you shouldn't be using a monad.
Reading their answers, I suppose their special feeling about Monad arises from the historical incident that Haskell community has happend to chose Monads in Kleisli category to solve their problem(IO etc.)
So, again, I think the usefulness of Monads mostly arises from Functors that we can embed many functions within the structure, and Monads is a little expansion for robustness of function composition by join
: M(M(X)) -> M(X)
to avoid the nested type.
In fact, in JavaScript I implemented as below..
Functor
console.log("Functor");
{
const unit = (val) => ({
// contextValue: () => val,
fmap: (f) => unit((() => {
//you can do pretty much anything here
const newVal = f(val);
// console.log(newVal); //IO in the functional context
return newVal;
})()),
});
const a = unit(3)
.fmap(x => x * 2) //6
.fmap(x => x + 1); //7
}
The point is we can implement whatever we like in the Functor structure, and in this case, I simply made it IO/console.log
the value.
Another point is, to do this Monads is absolutely unnecessary.
Monad
Now, based on the Functor implementation above, I add extra join: MMX => MX
feature to avoid the nested structure that should be helpful for robustness of complex functional composition.
The functionality is exactly identical to the Functor above, and please note the usage is also identical to the Functor fmap
. This does not require a "monadic function" to bind
(Kleisli composition of monads).
console.log("Monad");
{
const unit = (val) => ({
contextValue: () => val,
bind: (f) => {
//fmap value operation
const result = (() => {
//you can do pretty much anything here
const newVal = f(val);
console.log(newVal);
return newVal;
})();
//join: MMX => MX
return (result.contextValue !== undefined)//result is MX
? result //return MX
: unit(result) //result is X, so re-wrap and return MX
}
});
//the usage is identical to the Functor fmap.
const a = unit(3)
.bind(x => x * 2) //6
.bind(x => x + 1); //7
}
Monad Laws
Just in case, this implementation of the Monad satisfies the monad laws, and the Functor above does not.
console.log("Monad laws");
{
const unit = (val) => ({
contextValue: () => val,
bind: (f) => {
//fmap value operation
const result = (() => {
//you can do pretty much anything here
const newVal = f(val);
//console.log(newVal);
return newVal;
})();
//join: MMX => MX
return (result.contextValue !== undefined)
? result
: unit(result)
}
});
const M = unit;
const a = 1;
const f = a => (a * 2);
const g = a => (a + 1);
const log = m => console.log(m.contextValue()) && m;
log(
M(f(a))//==m , and f is not monadic
);//2
console.log("Left Identity");
log(
M(a).bind(f)
);//2
console.log("Right Identity");
log(
M(f(a))//m
.bind(M)// m.bind(M)
);//2
console.log("Associativity");
log(
M(5).bind(f).bind(g)
);//11
log(
M(5).bind(x => M(x).bind(f).bind(g))
);//11
}
So, here is my question.
I may be wrong.
Is there any counter example that Functors cannnot do what Monads can do except the robustness of functional composition by flattening the nested structure?
What's so special about Monads in Kleisli category? It seems like it's fairly possible to implement Monads with a little expansion to avoid the nested structure of Functor and without the monadic functions a -> m b
that is the entity in Kleisli category.
Thanks.
edit(2018-11-01)
Reading the answers, I agree it's not appropriate to perform console.log
inside the IdentityFunctor that should satisfy Functor-laws, so I commented out like the Monad code.
So, eliminating that problem, my question still holds:
Is there any counter example that Functors cannnot do what Monads can do except the robustness of functional composition by flattening the nested structure?
What's so special about Monads in Kleisli category? It seems like it's fairly possible to implement Monads with a little expansion to avoid the nested structure of Functor and without the monadic functions a -> m b
that is the entity in Kleisli category.
An answer from @DarthFennec is:
"Avoiding the nested type" is not in fact the purpose of
join
, it's just a neat side-effect. The way you put it makes it sound likejoin
just strips the outer type, but the monad's value is unchanged.
I believe "Avoiding the nested type" is not just a neat side-effect, but a definition of "join" of Monad in category theory,
the multiplication natural transformation μ:T∘T⇒T of the monad provides for each object X a morphism μX:T(T(X))→T(X)
monad (in computer science): Relation to monads in category theory
and that's exactly what my code does.
On the other hand,
This is not the case.
join
is the heart of a monad, and it's what allows the monad to do things.
I know many people implements monads in Haskell in this manner, but the fact is, there is Maybe functor in Haskell, that does not has join
, or there is Free monad that join
is embedded from the first place into the defined structure. They are objects that users define Functors to do things.
Therefore,
You can think of a functor as basically a container. There's an arbitrary inner type, and around it an outer structure that allows some variance, some extra values to "decorate" your inner value.
fmap
allows you to work on the things inside the container, the way you would work on them normally. This is basically the limit of what you can do with a functor.A monad is a functor with a special power: where
fmap
allows you to work on an inner value,bind
allows you to combine outer values in a consistent way. This is much more powerful than a simple functor.
These observation does not fit the fact of the existence of Maybe functor and Free monad.