[译]浅入浅出Monads

大多数关于monad的教程都和老太太的裹脚布一样,又臭、又长,说不清、道不明。固然我也不巨大,没法保证我写的肯定更清楚明了,更活泼,以至更屌?不过我最少能够肯定,我这篇更简约。糟蹋不了你若干时候的!

空话不多说,先看下面这个对象Foo。她就是个monad。你必定会受惊道:我擦,这是什么意思?不要急,故事要重新说,我们照样先来剖析下Foo究竟是怎样干活的:

function Foo(value) {
    this.get = ()=> value;
    this.map = fn => {
        let result = fn(value);
        return new Foo(result);
    };
}

Foo接收了一个value,而且一向都没转变她的值。Foo里供应了一个get要领使得外部挪用者能够猎取value,另有一个牛逼的要领叫mapmap接收另一个函数(handler)作为参数,然后用接收的这个新函数handler处置惩罚value,将效果再次传给Foo,末了将实例化的新Foo对象返回。

由于map返回一个Foo的实例,因而map的要领是能够被链式挪用的:

let one = new Foo(1);
let two = one.map(x => x + 7).map(x => x / 2).map(x => x - 2);
two.get() === 2;

链式挪用high不 high?她许可我们能够根据希冀,对x实行递次操纵,这类更“天然”的作风相对比下面这类猖獗嵌套的作风要好:

//嵌套组合的体式格局长这个模样,
//我们必需从右向左读,才得出结论
//而且你说实话,这作风,你喜好么?
let two = minusTwo(divideByTwo(addSeven(1)));

而且每个步骤里处置惩罚value到下一个Foo实例的逻辑我们都能够抽离出去。

再来看看另一个monad,我们权且称之为Bar吧:

function Bar(value) {
  this.get = ()=> value;
  this.map = fn => {
      let result = fn(value);
      console.log(result);
      return new Bar(result);
  };
}

假如这时候我有一系列操纵想递次作用在value上,而且还要在每次变化时打印出来新的value,就能够应用Bar把下面这类原始的,二逼的代码:

let stepOne = something(1);
console.log(stepOne);
let stepTwo = somethingElse(stepOne);
console.log(stepTwo);
let stepThree = somethingDifferent(stepTwo);
console.log(stepThree);

重组成下面这类文雅的,高端的模样了:

new Bar(1)
  .map(something)           // console >> logs new value
  .map(somethingElse)       // console >> logs new value
  .map(somethingDifferent); // console >> logs new value

如今你应当懂什么是monads。我完成信誉了哦!Monads能够大略的归结出下面这些划定规矩:

  1. monad总会包括一个值

  2. monad有一个map要领,而且该要领会接收一个函数(handler)作为参数

  3. map通过上一步提到的handler处置惩罚value(还可能有些其他逻辑),并猎取其效果

  4. map末了返回一个new [Monad],以完成链式挪用

现在能想到的就这些了。假如上述的例子你都理解了,那你就懂什么是Monads了。假如你还再等什么黑魔法或许惊异算法,那抱歉了,还真没有!

理论上,我们恣意修正map的完成,任何能够在各步骤handler之间的逻辑都行 - 比方:决议传什么内容到下一步,或许对上一步handler处置惩罚的效果做点儿什么。

空值搜检就是个不错的例子:

function Maybe(value) {
  this.get = ()=> value;
  this.map = fn => {
      if (value === null) {
          return new Maybe(null);
      } else {
          return new Maybe(fn(value));
      }
  };
}

这个完成里,map只在value为正当值(非空)时,传入handler。不然就只返回一个本身的copy。应用上面的非空搜检的Monad函数Maybe,我们能够把下面这个冗杂矬的代码:

let connection = getConnection();
let user = connection ? connection.getUser() : null;
let address = user ? user.getAddress() : null;
let zipCode = address ? address.getZip() : null;

重组成这个模样:

let zipCode =
    new Maybe(getConnection())
    .map(c => c.getUser())
    .map(u => u.getAddress())
    .map(a => a.getZip());

//末了获得的要么是真正的zipCode(每一步都正确处置惩罚)
//要么就是个null
zipCode.get();

愿望本日的说教已说清楚明了monads和她的map要领为何这么牛逼了!关于这点,我却是不怀疑你也能本身想出来^^

另有其他很多种monads,都有差别的用法和用处。但不论怎样变化,她们也都和FooBar一样恪守上面提到的划定规矩。

控制了这些技能,你基础就能够装做一个会写函数式的“牛人”了!

原文地点:Monads Explained Quickly

    原文作者:leftstick
    原文地址: https://segmentfault.com/a/1190000004895315
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞