I'm struggling with understanding the unit function in JavaScript. Particularly because the thing that made me 'get' monads (or at least I thought) was the Promise object, and how then
always returns a new Promise, regardless of what function you pass to then
, which, to my knowledge is equivalent to bind
or >>=
in haskell. This totally makes sense to me, because it ensures that all of your functions are executed in the 'monad universe', so to speak.
What's tripping me up is the 'Monads and Gonads' talk by Douglas Crockford. In his implementation, bind
directly returns the result of the transform function, without checking if the result itself, is a monad. This clashes with Promises's then
method, as then
ALWAYS returns a new Promise.
One thought was the lift method. His implementation does ensure that 'lift' will always return a monad, and maybe then
was lifted on to Promise. However, this would mean that then !== bind
, and that Promise has an internal bind somewhere.
My intuition is that there should at least be some sort of type check in the bind function that checks the result of the transformation, and allows a resulting monad to be let through, but will intercept non-monads and pass them through unit again, like 'lift' does.
*EDIT
Also, I'm under the impression that then
is equivalent to bind, flatMap, >>=
because it has the ability to unwrap other monads, including different ones and ones of it's own type. While looking in to some category theory references in JavaScript, flatMap
was used to map over a set of nested arrays, and then flatten them by one dimension. This fits with how then
will wait for other promises you give it. But doesn't seem to match up with the original implementation mentioned above. I feel lost.
Can anyone with more FP experience shed some light on what I'm missing, or am I just too off, and need to start from the beginning?
Some code examples...
// Crockford's 'bind'
monad.bind = function(transform) {
// value was passed in through the unit constructor
return transform(value);
}
My trouble area
// Set the 'isMonad' prop to be true, for all
// monads made with the MONAD macroid
monad.isMonad = true;
// shouldn't this ALWAYS return a monad?
monad.bind = function(transform) {
var res = transform(value);
return ( res && res.isMonad ) ? res : unit(res);
}
NOTE I know i'm not using the final version of his implementation in full, I'm just focusing in the bind method in particular.
The full implementation can be found at
https://github.com/douglascrockford/monad/blob/master/monad.js
Update
After doing some more research, >>=
is not required to return a Monad instance. Bergi's comment shed some light on how Promise.prototype.then
is overloaded and acts as a different function depending on what you resolve it with.
Also, a lot of things started to click when I took a step back and looked at how Monads are different from regular functors. The details are still a little fuzzy, but I think I get the big picture.
A few good references that helped clear the haze,
This one is highly recommend for a high level overview, in human words
http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html
Don't let the pictures fool you, this one was like gold for me. Not in JavaScript, but still very informative about the overall concepts.
Also, this YouTube series on Category Theory in JavaScript
https://www.youtube.com/watch?v=-FkgOHvNAU8&list=PLwuUlC2HlHGe7vmItFmrdBLn6p0AS8ALX&index=1
This YouTube series called 'Fun Fun Function' is wonderful, the host is one of the best teachers I've found online. This video is about monads and was suggested by MrE
.
Highly recommended!.
https://www.youtube.com/watch?v=9QveBbn7t_c&app=desktop
Those two references specifically did wonders for me. Hope that helps everyone else as well.