JavaScript函数式编程之函子( 二 )

IO函子这个_value属性他里面要去合并很多函数,所以他里面可能是不纯的 , 把这些不纯的操作延迟到了调用的时候,也就是我们通过IO函子控制了副作用的在可控的范围内发生

实现 liunx 下 cat 命令
const fp = require('lodash/fp')// IO 函子class IO {constructor (fn) {this._value = https://www.huyubaike.com/biancheng/fn}static of (value) {return new IO(function () {return value})}map (fn) {// 把当前的value 和传入的fn 函数组合成一个新的函数return new IO(fp.flowRight(fn, this._value))}}let r = IO.of(process).map(x => x.execPath)function readFile (fileName) {return new IO(() => fs.readFileSync(fileName,'utf-8'))}function print (x) {return new IO(() => {console.log(x)return x})}let cat = fp.flowRight(print, readFile)console.log(cat('package.json')._value()._value())此时IO函子出现了嵌套的问题,导致调用嵌套函子中的方法就必须要要._value()._value() 这样来执了,嵌套了几层就需要几层调用
FolktaleFolktale 是一个标准的函数式编程库,和lodash不同的是 , 他没有提供很多功能函数,只提供了一些函数式处理的操作,例如:compose、curry等 , 一些函子 Task、Either、MayBe等,
Folktale中的currycompose的简单使用
const { compose, curry } = require('folktale/core/lambda')const { toUpper, first } = require('lodash/fp')// 与lodash区别,第一个参数指明后面参数的个数let f = curry(2, (n1, n2) => n1 + n2)console.log(f(1, 2))// compose 就是函数组合 lodash 中的函数组合是 flowRightlet f2 = compose(toUpper, first)console.log(f2(['one', 'two']))Folktale 中的 task 函子函子可以处理异步任务,在异步任务中会通往地狱之门的回调,而使用task 函子可以避免回调的嵌套 , 详细请看官方文档
// Task 异步任务const { task } = require('folktale/concurrency/task')const { split, find } = require('lodash/fp')const fs = require('fs')function readFile (filename) {return task(resolver => {fs.readFile(filename, 'utf-8', (err, data) => {if (err) {resolver.reject(err)}resolver.resolve(data)})})}readFile('package.json').map(split('\n')).map(find(x => x.includes('version')))// 执行读取文件.run().listen({onRejected(err) {console.log(err)},onResolved(value) {console.log(value)}})Pointed函子Pointed函子 是实现了of静态方法 ,  of 方法是为了避免使用new 来创建对象,更深层次含义是of方法把值放到上下文Context(把值放到容器中,使用map 来处理值)
class Container {constructor (value) {this._value = https://www.huyubaike.com/biancheng/value} static of () {return new Container(value)}map (fn) {return new Container(fn(this._value))}}Monad函子解决函子嵌套的问题,Monad 函子是可以变扁的 Pointed 函子 IO(IO),一个函子如果具有joinof两个方法并遵循一些定律就是一个Monad
class IO {constructor (fn) {this._value = https://www.huyubaike.com/biancheng/fn}static of (value) {return new IO(function () {return value})}map (fn) {return new IO(fp.flowRight(fn, this._value))}join () {return this._value()}// 同时调用 join 和 mapflatMap (fn) {return this.map(fn).join()}}function readFile (fileName) {return new IO(() => fs.readFileSync(fileName,'utf-8'))}function print (x) {return new IO(() => {return x})}let r = readFile('package.json').flatMap(print).join()console.log(r)当我们想要去调用一个方法,这个方法返回一值的时候我们去调用map方法,当我们想要去调用一个方法,这个方法返回一个函子的时候我们去调用flatMap方法
原文地址:https://kspf.xyz/archives/17更多内容微信公众号搜索充饥的泡饭小程序搜一搜开水泡饭的博客

推荐阅读