美文网首页
JS函数式编程03--函子

JS函数式编程03--函子

作者: 小q | 来源:发表于2020-06-12 15:00 被阅读0次

函子

函子的概念

函子是函数式编程里面最重要的数据类型,也是基本的运算单位和功能单位。
函子首先是一个容器,它包含了值和值的变形关系,这个变形关系就是函数。
函子可以把函数式编程副作用控制在可控的范围内,包括处理异常,异步操作等。
一般约定,函子的标志就是容器具有map方法。该方法将容器里面的每一个值,映射到另一个容器。

函子的基本构造

函子就是一个特殊的容器,它可以由对象来实现,这个对象中包含了值,这个值永远不会对外公布,有一个map方法,用来操作这个值。还有一个of方法,用来生成一个新的容器。

class Functor {
  static of(value){
    return new Functor(value)
  }

  constructor(val){
    this._value = val
  }

  map(fn){
    return Functor.of(fn(this._value ))
  }
}

//使用的时候
const func = Functor.of.map(x => x+1)
func(1)//Container { _value: 2 }

这里总结一下函子的使用

  • 程序运算不会直接操作值,而是通过函子来完成
  • 由map处理后返回的是一个新的对象,我们可以继续链式的操作值
  • 我们可以把函子想象成一个盒子,盒子中封装着一个值,当我恩处理盒子中的值的时候我们要用到盒子专门改变值的工具:map,我们需要给盒子的map方法传递一个处理值的函数(纯函数),由这个函数来对值进行处理,最终map方法返回一个包含新值的盒子(函子)。

MayBe函子

函子会接收各种函数来处理内部的值,这里就有可能遇到错误,我们需要对这些错误做处理,MayBe函子的作用就是对外部的空值情况做处理。

MayBe函子的构造就是在map中设置空值检查

  class Maybe{
    static of(value){
      return new Maybe(value)
    }

    constructor(val){
      this._value = val
    }
    map(f) {
      return this.val ? Maybe.of(f(this.val)) : Maybe.of(null);
    }
  }

虽然 MayBe函子可以避免出现错误,但是多次调用map时我们并不知道哪里出现了错误

Either函子

Either函子与if...else处理很相似。它内部有两个值,左值和右值。右值通常代表正常的值,左值是当右值不存在或错误时的默认值

  class Either {
     static of(left,right){
      return new Either (left,right))
    }
    constructor(left,right){
      this.left = left
      this.right = right
    }
    map(fn){
      return this.right ? Either.of(this.left,fn(this.right)) : Either.of(fn(this.left),right)
    }
  }

此外,Either函子另一个用途是替代try...catch,使用左值来表示错误

  function parseJSON(json) {
  try {
    return Either.of(null, JSON.parse(json));
  } catch (e: Error) {
    return Either.of(e, null);
  }
}

ap函子

函子中的值有可能是数值,也有可能是一个函数,我们想让值为函数的函子用另一个函子中的值运算,我们就可以用ap函子

  function add(x) {
    return x + 1
  }
  const A = Functor.of(2)
  const B = Functor.of(add)

  class Ap extends Functor {
    ap(F) {
      return Ap.of(this.val(F.val))
    }
  }

   //我们想让B函子的值使用A函子的值
  Ap.of(add).ap(Functor.of(2))

凡是部署了ap方法的函子,就是ap函子。ap函子的意义在于对多参数的函数,可以从多个容器中取值,实现函子的链式调用。

Monad 函子

函子中的值可以接受任何值,所以函子之中可以包含另一个函子。这样就会造成函子多层嵌套的问题。取值时会很不方便。Monad函子的作用就是:总是返回一个单层的函子,它有一个FlatMap方法,与map方法作用相同,唯一的区别就是如果生成了一个嵌套函子,它会取出后者的值,保证返回的永远是一个单层的容器,不会出现嵌套的情况。

  class Monad extends Functor {
    join() {
      return this.val;
    }
    flatMap(f) {//f是一个函子
      return this.map(f).join();
    }
  }

如果函数f返回的是一个函子,那么this.map(f)就会生成一个嵌套的函子。所以,join方法保证了flatMap方法总是返回一个单层的函子。这意味着嵌套的函子会被铺平。

IO函子

I/O是一个不纯的操作,普通的函数式编程无法处理,所以使用IO函子操作

const fp = require('lodash/fp')
class IO {
    static of (value) {
        return new IO (function () {
            return value
        })
    }

    constructor(fn) {
        this._value = fn
    }

    map (fn){
        return new IO (fp.flowRight(fn,this._value));
    }
}
  • IO函子中的_value是一个一个函数,这里是把函数作为值来处理
  • IO函子可以把不纯的动作存储到_value中,延迟这个不纯的操作(惰性执行),包装当前的操作是纯的操作
  • 把不纯的操作交给调用者来处理。

参考

函数式编程入门教程

相关文章

  • JS函数式编程03--函子

    函子 函子的概念 函子是函数式编程里面最重要的数据类型,也是基本的运算单位和功能单位。函子首先是一个容器,它包含了...

  • 深入浅出Rxjs笔记 一

    一.函数式编程 函数式编程要求: 声明式 纯函数 数据不可变js 不算纯粹意义上的函数式编程语言,但是,在js中函...

  • 函数式编程小思考4.2 笔记

    函数式编程小思考4 笔记JS函数式编程指南Data.Task 函子 源码 补充两个内容 用得到的curry函数 文...

  • Functor函子

    为什么学习函子? 函子是函数式编程里面最重要的数据类型,也是基本的运算单位和功能单位 函子作用:控制函数式编程中的...

  • 函数式编程概念总结

    函数式编程 对应于 命令式编程诞生。 函数式编程 强调数据流。强调计算什么,而不是怎么计算。 就是从函子(容器)传...

  • 函数式编程——Functor、Applicative、Monad

    原文链接 了解函数式编程的同学可能或多或少都听说过 函子(Functor)、适用函子(Applicative)、单...

  • 函子的概念

    一、函子 为什么要学习函子? 到目前为止已经学习了函数式编程的一些基础,但是我们还没有演示在函数式编程中如何把副作...

  • Python-函数式编程

    函数式编程简介 一、什么是函数式编程? 函数:function函数式:functional,是一种编程范式 二、函...

  • 浅析函数式编程

    一:什么是函数式编程 函数式编程(英语:functional programming)或称函数程序设计、泛函编程,...

  • JS进阶 -- 面向对象(二)构造函数 + 继承

    概述 本篇主要讲述构造函数和继承 构造函数 编程 编程主要分为函数式编程和面向对象编程 函数式编程 ==> 推崇函...

网友评论

      本文标题:JS函数式编程03--函子

      本文链接:https://www.haomeiwen.com/subject/cppbtktx.html