问题:IO函子其实主要是一种过滤器的写法,又称为 “垃圾桶”,意思是将不纯的行为丢进垃圾桶,即IO函子
我们可以看下这个案例
/*** 如果组合函数返回的是函子,那么容易造成函子嵌套的问题*/const fs = require("fs");const { flowRight } = require("lodash/fp");class IO {static of(value) {return new IO(value);}constructor(value) {this._value = value;}map(fn) {return new IO(flowRight(fn, this._value));}}// 读文件const readFile = (filename) => {return new IO(() => fs.readFileSync(filename, "utf-8"));};// 查看文件const print = (value) => {// console.log('value',value) // value IO { _value: [Function (anonymous)] }return new IO(() => value);};// readFile返回函子, print返回函子,IO(IO(X))/*** 1. 调用flowRight(print, readFile)时,组合函数从右到左执行,readFile 返回一个函子,print 接收 readFile 返回的函子* 2. print 执行 参数value是 readFile返回的函子,自身 retrun 一个函子* 3. flowRight最终返回的是一个函子里包含着函子,这是一种嵌套函子*/const v = flowRight(print, readFile);// 嵌套多重函子,蹩脚的写法,IO函子的局限性,当出现多重函子时,可读性不高const r = v("package.json")._value()._value();console.log(r);
得知 :
- 读文件和查看文件, 这两个函数是不纯的行为
- 为了解决不纯, 将这种行为丢进IO函子中, 通过函数包裹操作文件的逻辑传进去, 并且返回一个新的IO函子
- 将两个操作函数进行整合成一个组合函数
- 调用组合函数,率先执行readFile方法,那么会返回一个函子,这个函子会被print接送, 然而print也会返回一个函子,接收的参数又是一个函子
- 最后print将这个函子传递到IO函子中,并返回一个新的IO函子,得到的是一个函子嵌套函子
问题显而易见:
- 函数嵌套函数,可以用函数组合来整合
- 函子嵌套函子,怎么解决?
答复:
- 可以直接调用函子返回的_value方法,嵌套多少层,就调用多少层
- 使用monad函子,处理函子嵌套函子
