_value
中,延迟这个不纯的操作(惰性执行),保证当前的操作是纯的,延迟把不纯的操作到调用者来处理
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)console.log(r)console.log(r._value())
IO 函子内部帮我们包装了一些函数,当我们传递函数的时候有可能这个函数是一个不纯的操作,不管这个函数纯与不纯,IO这个函子在执行的过程中它返回的这个结果始终是一个纯的操作,我们调用map
的时候始终返回的是一个函子,但是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中的
curry
与compose
的简单使用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)
,一个函子如果具有
经验总结扩展阅读
- Java函数式编程:一、函数式接口,lambda表达式和方法引用
- Vue3 SFC 和 TSX 方式调用子组件中的函数
- C++ 函数重载解析策略
- 火漆可以用来干嘛
- 原生JavaScript
- 钩子 【pytest官方文档】解读-插件开发之hooks 函数
- Java 最长公共前缀
- TCP和UDP的区别与联系以及网络字节序和主机字节序的转换函数实践
- Python函数-2V2
- 三角函数正切公式