[译]浅入浅出Monads

news/2024/7/4 15:41:42

大多数关于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


http://www.niftyadmin.cn/n/4356450.html

相关文章

指针+数组=指针数组

指针–>数组—>指针数组 指针 什么是指针?在计算机科学中,指针(Pointer)是编程语言的一个对象,利用地址,它的值直接指向(Pointer)存在电脑存储器中另一个地方的值。由于通过地…

mysql手工安装_Linux下手工安装MySQL

安装环境:Linux服务器CentOS 5.5安装版本:mysql-5.5.8.tar.gz1、安装 cmake 编译器。1)、下载cmake#cd /usr/local/src#wget http://www.cmake.org/files/v2.8/cmake-2.8.4.tar.gz2)、解压cmake#tar -zvxf cmake-2.8.4.tar.gz3)、配置编译#cd cmake-2.8.…

Linux背景及基础命令

Linux初识 linux背景 multics 肯汤普森 》 nuix Andrew S Tanenbaum 》 minux 李纳斯托瓦丝 》linux 1991 》1994 Linux 1.0 GNU 开源免费 稳定免费 版本碎片化 缺点:可以运行在9.0 不能再5.0系统运行 ↓ linux 与 发行版linux ↓ linux内核 ↓ 操作系统 内核 …

C++学习之const修饰成员函数

常函数&#xff1a; 成员函数后加const后我们称为这个函数为常函数常函数内不可以修改成员属性成员属性声明时加关键字mutable后&#xff0c;在常函数中依然可以修改 常对象&#xff1a; 声明对象前加const称该对象为常对象常对象只能调用常函数 #include<iostream> …

淘淘商城系列——实现图片上传功能

原文地址&#xff1a;https://blog.csdn.net/yerenyuan_pku/article/details/72808000上文我们使用FastDFS-Client进行了简单的文件上传操作测试&#xff0c;淘淘商城项目中添加商品时上传图片的功能还没实现&#xff0c;如下图所示。本文将花大量笔墨来教大家如何实现图片上传…

常用语言的编译器

C/C编译器 首先是如雷贯耳的这几位仁兄&#xff0c;MSVC、GCC、Cygwin、MingW&#xff08;Cygwin和MingW的英文发音&#xff09;&#xff0c;另外还有些小众和新秀&#xff0c;像ICC&#xff08;Intel C/C Compiler&#xff09;、BCC&#xff08;Borland C/C Compiler&#xf…

Linux中环境变量的设置——setenv/export

Linux中环境变量的设置——setenv/export 环境变量 境变量&#xff08;environment variables&#xff09;一般是指在操作系统中用来指定操作系统运行环境的一些参数&#xff0c;如&#xff1a;临时文件夹位置和系统文件夹位置等。 环境变量是在操作系统中一个具有特定名字的…

电商系统中购物车-订单-支付流程

原文地址&#xff1a;https://blog.csdn.net/Cpath/article/details/72872258/*** 电商 购物车--订单--支付*/#用户登陆--未登录#pc/wap #1、根据客户端ip 设置session_id保证用户唯一标识#[分析用户行为] #2、缓存用户操作记录[记录用户在页面停留的时间分析用户行为]友盟---…