一、pointfree

把数据处理的过程定义成与数据无关的合成运算,不需要用到代表数据的参数,只需将运算步骤合成,使用之前需定义一些辅助运算函数

  • 不需要指明处理的数据
  • 需要合成运算过程
  • 需要定义一些辅助的基本运算函数

这就是函数组合,只是更加抽象

  1. const f1 = fp.flowRight(fp.join('-'), fp.map(fp.toLower), fp.split(' '))
  2. const f2 = fp.flowRight(fp.replace(/\s+/g, '_'), fp.toLower)
  3. f2('HELLO WORLD')
  4. -----------------------
  5. //world wild web => W. W. W
  6. const change = fp.flowRight(fp.join('. '), fp.map(
  7. fp.flowRight(fp.first, fp.toUpper)
  8. ), fp.split(' '))
  9. change('world wild web')

二、Functor 函子

如何在函数式编程中把副作用控制在可控范围内、异常处理、异步操作等
定义
容器:包含值和值的变形关系(这个关系就是函数)
函子:一个特殊的容器,通过一个普通对象来实现,具有map方法,可以运算一个函数对值进行处理(变形关系)

  1. class Container{
  2. static of(value){
  3. return new Container(value)
  4. }
  5. constructor(value){
  6. this._value = value
  7. }
  8. map(fn){
  9. //return new Container(fn(this._value))
  10. return Container.of(fn(this._value))
  11. }
  12. }
  13. //let r = new Container(5).map(x => x + 1).map(x => x * x)
  14. let r = Container.of(5).map(x => x + 1).map(x => x * x)

总结
函数式编程的运算不直接操作值,而是由函子完成
函子就是一个实现了map契约的对象
可以把函子当成一个盒子,盒子里封装了一个值
处理盒子中的值,需给盒子的map方法传递一个处理值的函数
map方法最终返回一个包含新值的盒子(函子)

三、maybe函子

  • 编程过程中可能会遇到很多错误,需对此进行处理
  • maybe函子的作用就是可以对外部的空值情况处理
  • 多次调用时,出现了null,无法确定是在哪一步出现,调试不便
    1. class MayBe{
    2. static of(value){
    3. return new MayBe(value)
    4. }
    5. constructor(value){
    6. this._value = value
    7. }
    8. map(fn){
    9. return this.isNothing()? MayBe.of(null):MayBe.of(fn(this._value))
    10. }
    11. isNothing(){
    12. return this._value === null || this._value === undefined
    13. }
    14. }

    四、Either函子

    两者中的任何一个,用来做异常处理 ```javascript class Left{ static of(value){
    1. return new Left(value)
    } constructor(value){
    1. this._value = value
    } map(fn){
    1. return this
    } } class Right{ static of(value){
    1. return new Right(value)
    } constructor(value){
    1. this._value = value
    } map(fn){
    1. return Right.of(fn(this._value))
    } }

function parseJSON(str){ try{ return Right.of(JSON.parse(str)) }catch(e){ return Left.of({error: e.message}) } } let r1 = parseJSON(‘{name : zs}’) let r2 = parseJSON(‘{“name” : “zs”}’) let r3 = parseJSON(‘{“name” : “zs”}’).map(x => x.name.toUpperCase())

  1. <a name="4coAA"></a>
  2. # 五、Task异步执行
  3. - forktale一个标准的函数式编程库
  4. - 只提供了一些函数式处理操作,如:compose、curry等。一些函子Task,Either、MayBe等
  5. ```javascript
  6. const {compose, curry} = require('forktale/core/lambda')
  7. const {toUpper, first} = require('lodash/fp')
  8. let f1 = curry(2, (x, y) => x+y)
  9. console.log(f1(1,2))
  10. console.log(f1(1)(2))
  11. let f2 = compose(toUpper, first)
  12. console.log(f2(['one', 'two']))

Task函子

  1. const {task} = require('forktale/concurrency/task')
  2. const fs = require('fs')
  3. const {split, find} = require('lodash/fp')
  4. function readFile(filePath){
  5. return task(resolver => {
  6. fs.readFile(filePath,'utf-8',(error, data) => {
  7. if (error) resolver.reject(error)
  8. resolver.resolve(data)
  9. })
  10. })
  11. }
  12. readFile('package.json')
  13. .map(split('\n'))
  14. .map(find(x => x.includes('version')))
  15. .run().listen({
  16. onRejected: err => {
  17. console.log(err)
  18. },
  19. onResolved: value => {
  20. console.log(value)
  21. }
  22. })

六、Pointed函子

实现了of静态方法的函子
of方法是为了避免使用new来创建对象,更深层的含义是of方法用来把值放到上下文
把值放到容器中,使用map来处理值

七、IO函子

IO函子的_value是一个函数,这里是把函数作为值来处理
IO函子可以把不纯的动作存到_value中,延迟执行这个不纯的操作(惰性执行)
把不纯的操作交给调用者来执行

  1. class IO{
  2. static of(x){
  3. return new IO(function() {
  4. return x
  5. })
  6. }
  7. constructor(fn){
  8. this._value = fn
  9. }
  10. map(fn){
  11. return new IO(fp.flowRight(fn, this._value))
  12. }
  13. }
  14. let r = IO.of(process).map(p => p.execPath)
  15. console.log(r._value)
  1. let readFile = function(filePath){
  2. return new IO(function(){
  3. return fs.readFileSync(filePath,'utf-8')
  4. })
  5. }
  6. let print = function(x){
  7. return new IO(function(){
  8. console.log(x)
  9. return x
  10. })
  11. }
  12. let cat = fp.flowRight(print, readFile)
  13. //IO(IO(x)) 函子嵌套时调用value不方便
  14. let r = cat('package.json')._value()._value()

八、Monad函子

Monad函子是可以变扁的Pointed函子
一个函子如果具有join和of两个方法并遵守一些定律就是一个Monad

  1. class IO{
  2. static of(x){
  3. return new IO(function() {
  4. return x
  5. })
  6. }
  7. constructor(fn){
  8. this._value = fn
  9. }
  10. map(fn){
  11. return new IO(fp.flowRight(fn, this._value))
  12. }
  13. join(){
  14. return this._value()
  15. }
  16. flatMap(fn){
  17. return this.map(fn).join()
  18. }
  19. }