Did you make promise monad

Time:2021-8-28

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->cSum 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

Did you make promise monad

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.

Did you make promise monad

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

Complete code


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"

Complete code

What’s the use, monad

Let’s summarize the difference between the two approaches:

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

  2. 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

  3. 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$.ajaxYes, 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 returnDeferredType 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 againWire-walking:

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

ref: Functional JavaScript Chapter 4

Recommended Today

Java Engineer Interview Questions

The content covers: Java, mybatis, zookeeper, Dubbo, elasticsearch, memcached, redis, mysql, spring, spring boot, springcloud, rabbitmq, Kafka, Linux, etcMybatis interview questions1. What is mybatis?1. Mybatis is a semi ORM (object relational mapping) framework. It encapsulates JDBC internally. During development, you only need to pay attention to the SQL statement itself, and you don’t need to […]