问题: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函子,处理函子嵌套函子