从函数式编程到Promise

原创 Fundebug 随笔 Fundebug 50阅读 2018-11-14 15:58:40 举报

原文: Functional Computational Thinking — What is a monad?

译者: Fundebug

为了保证可读性,本文采用意译而非直译。另外,本文版权归原作者所有,翻译仅用于学习。

如果你使用函数式编程,不管有没有用过函数式语言,在某总程度上已经使用过Monad。可能大多数人都不知道什么叫做Monad。在这篇文章中,我不会用数学公式来解释什么是Moand,也不使用Haskell,而是用JavaScript直接写Monad。

作为一个函数式程序员,我首先来介绍一下基础的复合函数:

复合函数composeF接收fg两个参数,然后返回值是一个函数。该函数接收一个参数x, 先将函数g作用到x, 其返回值作为另一个函数f的输入。

addOneThenMul3是我们通过composeF定义的一个新的函数:由mul3add1复合而成。

接下来看另一个实际的例子:我们有两个文件,第一个文件存储了第二个文件的路径,第二个文件包含了我们想要取出来的内容。使用刚刚定义的复合函数composeF, 我们可以简单的搞定:

readFileSync是一个阻塞函数,接收一个参数path,并返回文件中的内容。我们使用composeF函数将两个readFileSync复合起来,就达到我们的目的。是不是很简洁?

但如果readFile函数是异步的呢?如果你用Node.js 写过代码的话,应该对回调很熟悉。在函数式语言里面,有一个更加正式的名字:continuation-passing style 或则 CPS。

我们通过如下函数读取文件内容:

但是有一个问题:我们不能使用composeF了。因为readCPS函数本身不在返回任何东西。
我们可以重新定义一个复合函数composeCPS,如下:

注意:在composeCPS中,我交换了参数的顺序。composeCPS会首先调用函数g,在g的回调函数中,再调用f, 最终通过cb返回值。

接下来,我们来一步一步改进我们定义的函数。

第一步,我们稍微改写一下readFIleCPS函数:

HOF是 High Order Function (高阶函数)的缩写。我们可以这样理解readFileHOF: 接收一个为path的参数,返回一个新的函数。该函数接收cb作为参数,并调用readFileCPS函数。

并且,定义一个新的复合函数:

第二步,我们接着改进readFileHOF函数:

readFileEXEC函数返回一个对象,对象中包含一个exec属性,而且exec是一个函数。

同样,我们再改进复合函数:

现在我们来定义一个帮助函数:

该函数返回一个对象,包含一个exec属性。
我们使用该函数来优化readFileEXEC函数:

readFileEXEC2接收一个path参数,返回一个exec对象。

接下来,我们要做出重大改进,请注意!
迄今为止,所有的复合函数的两个参数都是函数,接下来我们把第一个参数改成exec对象。

bindExec函数返回一个新的exec对象。

我们使用bindExec来定义读写文件的函数:

如果不是很清楚,我们可以这样写:

我们接下来把bindExec函数放入exec对象中:

如何使用呢?

这已经和在函数式语言Haskell里面使用Monad几乎一模一样了。

我们来做点重命名:

  • readFileEXEC2 -> readFileAsync
  • bind -> then
  • exec -> done

发现了吗?竟然是Promise!

Monad在哪里呢?

composeCPS开始,都是Monad.

  • readFIleCPS是Monad。事实上,它在Haskell里面被称作Cont Monad
  • exec 对象是一个Monad。事实上,它在Haskell里面被称作IO Monad

Monad 有什么性质呢?

  1. 它有一个环境;
  2. 这个环境里面不一定有值;
  3. 提供一个获取该值的方法;
  4. 有一个bind函数可以把值从第一个参数Monad中取出来,并调用第二个参数函数。第二个函数要返回一个Monad。并且该返回的Monad类型要和第一个参数相同。

数组也可以成为Monad

我们可以验证:

  1. [] 是环境
  2. []可以为空,值不一定存在;
  3. 通过forEach可以获取;
  4. 我们定义了flatMap来作为bind函数。

结论

  • Monad是回调函数 ?
    根据性质3,是的。
  • 回调函数式Monad?
    不是,除非有定义bind函数。

关于Fundebug

Fundebug专注于JavaScript、微信小程序、微信小游戏、支付宝小程序、React Native、Node.js和Java实时BUG监控。 自从2016年双十一正式上线,Fundebug累计处理了7亿+错误事件,得到了Google、360、金山软件、百姓网等众多知名用户的认可。欢迎免费试用!

版权声明

转载时请注明作者Fundebug以及本文地址:
https://blog.fundebug.com/2017/06/21/write-monad-in-js/

评论 ( 0 )
最新评论
暂无评论

赶紧努力消灭 0 回复