[译]浅入浅出Monads

大多数关于monad的教程都和老太太的裹脚布同样,又臭、又长,说不清、道不明。固然我也不伟大,无法保证我写的必定更明了,更生动,甚至更屌?不过我至少能够肯定,我这篇更简洁。浪费不了你多少时间的!javascript

废话很少说,先看下面这个对象Foo。她就是个monad。你一定会吃惊道:我擦,这是什么意思?不要急,故事要从头说,咱们仍是先来分析下Foo究竟是怎么干活的:java

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的方法是能够被链式调用的:ide

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实例的逻辑咱们均可以抽离出去。ui

再来看看另外一个monad,咱们姑且称之为Bar吧:this

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

若是这时候我有一系列操做想顺序做用在value上,并且还要在每次变化时打印出来新的value,就能够利用Bar把下面这种原始的,二逼的代码:code

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能够粗略的概括出下面这些规则:blog

  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

相关文章
相关标签/搜索