Monad is a difficult concept to explain. You can understand it as a lazy or unknown box. It sounds likeSchrodinger cat(it’s estimated that you will feel more dizzy when you go in). In fact, before you open the box, you don’t know what kind of state the cat is in
Monad is a black box. We have to open it and drink it before we know
Wait, didn’t you say you want to explain either? Uh huh, this is to explain either. Last section said either is a functor and can be fmap over. Why does it say black box again? Well, monad is actually functor. Remember that functor is actually a box with context. Fmap makes it possible to apply function transformation to the box
Either
Let’s take a look at what this type of either can doEither It means either the left or the right value, so we can use it to represent the Schrodinger cat. If it is not alive, it will not die. Either has another method:
either
(a > c) > (b > c) > Either a b > c
You must have been right>
Very familiar. If you skip the previous chapters, I’ll translate it again. This represents the receiving functiona>c
Sum function b>c
, and then receive an either. If the value of either is on the left, the function mapping is used a>c
, if the value is on the right, the second function mapping is applied b>c
.
As monad, it must also have a method ‘> =’ (the symbol is familiar. Look at Haskell’s logo and you will know how important monad is), that is, the bind method
The bind method simply means to add an operation to the box, such as adding radioactive atoms to the box. If the cat is alive, it is the green giant cat. If the cat is dead, it is the green giant dead cat
Left("cat").bind(cat => 'hulk'+cat)
// => Left "hulkcat"
Right("deadcat").bind(cat => 'hulk' + cat)
// => Right "hulkdeadcat"
It’s useful. It’s urgent… Let’s take a classic example
Cable walking
Pierce decided to quit his job and try to walk the tightrope. He’s good at tightrope walking, but there’s still a small problem. The bird will stop on the balance pole he holds. They’ll fly over, stop for a while, and then fly away. This is not a big problem when the number of birds on both sides is the same. But sometimes, when all the birds want to stop on the same side, pierce loses his balance and makes him fall off the wire rope.
Let’s assume that pierce can still keep a balance when the difference between the birds on both sides is within three.
General solution
First, let’s see how monad can solve it
eweda.installTo(this);
var landLeft = eweda.curry(function(n, pole){
return [pole[0]+n, pole[1]];
});
var landRight = eweda.curry(function(n, pole){
return landLeft(n, eweda.reverse(pole));
});
var result = eweda.pipe(landLeft(1), landRight(1), landLeft(2))([0,0]);
console.log(result);
// => [3, 1]
There is still an operation to judge whether pierce fell
var landLeft = eweda.curry(function(n, pole){
if(pole==='dead') return pole;
if(Math.abs(pole[0]pole[1]) > 3)
return 'dead';
return [pole[0]+n, pole[1]];
});
var landRight = eweda.curry(function(n, pole){
if(pole==='dead') return pole;
return landLeft(n, eweda.reverse(pole));
});
var result = eweda.pipe(landLeft(10), landRight(1), landRight(8))([0,0]);
console.log(result);
// => dead
Now try either
Let’s put pierce into the either box first, so that Pierce’s state can be seen only when either is opened. Assuming either right is alive and left, pierce hangs up
var land = eweda.curry(function(lr, n, pole){
pole[lr] = pole[lr] + n;
if(Math.abs(pole[0]pole[1]) > 3) {
return new Left("dead when land " + n + " became " + pole);
}
return new Right(pole);
});
var landLeft = land(0)
var landRight = land(1);
Now after the bird falls, it will return an either, either alive or dead. The function to open the box can be like this
var stillAlive = function(x){
console.log(x)
}
var dead = function(x){
Console.log ('pierce '+ x);
}
either(dead, stillAlive, landLeft(2, [0,0]))
Well, it seems a little like it, but this bird only falls once. If I want to fall several times, I need to implement either’s > > = bind method. If you remember the previously implemented functor, it is very similar:
var Monad = function(type, defs) {
for (name in defs){
type.prototype[name] = defs[name];
}
return type;
};
function Left(value){
this.value = value
}
function Right(value){
this.value=value;
}
Monad(Right, {
bind:function(fn){
return fn(this.value)
}
})
Monad(Left, {
bind: function(fn){
return this;
}
})
Oh, by the way, either:
either = function(left, right, either){
if(either.constructor.name === 'Right')
return right(either.value)
else
return left(either.value)
}
Let’s try to work or not
var walkInLine = new Right([0,0]);
eitherDeadOrNot = walkInLine.bind(landLeft(2))
.bind(landRight(5))
either(dead, stillAlive, eitherDeadOrNot)
// => [2,5]
eitherDeadOrNot = walkInLine.bind(landLeft(2))
.bind(landRight(5))
.bind(landLeft(3))
.bind(landLeft(10)
.bind(landRight(10)))
either(dead, stillAlive, eitherDeadOrNot)
//= > "pierce dead when land 10 became 15,5"
What’s the use, monad
Let’s summarize the difference between the two approaches:

In general, check whether Charles hangs or not every time, that is, repeatedly obtain the context of the previous operation

Monad doesn’t handle exceptions, just keeps adding operations to the box. You can see that the handling of errors is pushed to the last value of either

Monad only passes boxes to each other, and the general writing will pass exceptions down, such as
"dead"
In this way, the following operations must first judge the exception
commentBecause it is JavaScript, pole does not limit the type, so here we simply use string to represent the abnormal state of pole. However, if we change to strongly typed Java, the implementation may not be so simple
It seems that the advantage has gradually become obvious. Monad retains the context of value, that is, we can focus on how to operate value this time instead of context
There’s another monad called maybe, actually pierce’s
Application of monad in JavaScript
You know there’s a new type of ES6PromiseWell, if you don’t know, you must have heard of jQuery$.ajax
Yes, but if you haven’t heard promise, it means you haven’t carefully read its return value:
var aPromise = $.ajax({
url: "https://api.github.com/users/jcouyang/gists"
dataType: 'jsonp'
})
aPromise /***
=> Object { state: .Deferred/r.state(),
always: .Deferred/r.always(),
then: .Deferred/r.then(),
promise: .Deferred/r.promise(),
pipe: .Deferred/r.then(),
done: b.Callbacks/p.add(),
fail: b.Callbacks/p.add(),
progress: b.Callbacks/p.add() }
***/
We saw a lot of returnDeferred
Type of thing. Let’s try what this thing does
anotherPromise = aPromise.then(_ => _.data.forEach(y=> console.log(y.description)))
/* =>
Object { state: .Deferred/r.state(),
always: .Deferred/r.always(),
then: .Deferred/r.then(),
promise: .Deferred/r.promise(),
pipe: .Deferred/r.then(),
done: b.Callbacks/p.add(),
fail: b.Callbacks/p.add(),
progress: b.Callbacks/p.add() }
"connect cisco anyconnect in terminal"
"Why curry?"
"Get Renren movie download link in batch"
......
*/
See, he returns the same thing again, and the function passed to then can manipulate the value in this object. This object is actually promise. Why is this monad? Let’s try writing it againWirewalking
:
Here we use the promise of ES6 instead of jQuery deferred. Remember to use Firefox. In addition, eweda can be installed like this
var ewd = document.createElement('script'); ewd.type = 'text/javascript'; ewd.async = true;
ewd.src = 'https://rawgit.com/CrossEye/eweda/master/eweda.js';
(document.getElementsByTagName('head')[0]  document.getElementsByTagName('body')[0]).appendChild(ewd);
eweda.installTo(this); // Install to window
var land = curry(function(lr, n, pole){
pole[lr] = pole[lr] + n;
if(Math.abs(pole[0]pole[1]) > 3) {
return new Promise((resovle,reject)=>reject("dead when land " + n + " became " + pole));
}
return new Promise((resolve,reject)=>resolve(pole));
});
var landLeft = land(0)
var landRight = land(1);
Promise.all([0,0])
.then(landLeft(2), _=>_)
.then(landRight(3), _=>_) // => Array [ 2, 3 ]
.then(landLeft(10), _=>_)
.then(landRight(10), _=>_)
.then(_=>console.log(_),_=>console.log(_))
// => "dead when land 10 became 12,3"
Now we don’t recognize promise as monad. It turns out that we have been using this mysterious monad for a long time. When we think about promise, it’s not so abstract and mysterious