函数式编程

  • 函数式编程
    • 函数式编程思想
      • 程序 = 快照(状态) + 计算
      • 快照
        • 不可变性:不可变性在减少程序被外界影响的同时减少对外界的影响
          • 不可变变量
          • 纯函数:值保证不会显式改变一个量,而纯函数保证的是,不会隐式改变一个量
      • 计算
        • 抽象声明;计算组合,函数式更关系逻辑本身
        • 分离可变状态、副作用
    • 优点
      • 可测试性
      • 并发性性
      • 可维护性和可重用性
    • 特征
      • 纯函数:函数式编程中的函数指的是数学中的函数,即一个输入到输出的映射
        • 给定相同的输入,总是返回相同的输出:意味着函数的结果只能依赖于输入参数的变化,而与外部环境无关
        • 无副作用:副作用是指根据参数计算返回值之外的作业,比如 IO 操作、全局状态修改等这些对外部修改状态的行为
      • 不可变变量:函数式编程语言中的变量不是命令式编程语言中的变量,即存储状态的单元,而是代数中的变量,即某个符号所对应的值是永远不变的,也就是给值绑定命名
      • 函数是一等公民:函数是一等公民,强调使用高阶函数组合其他函数,将多个函数组合成一个更复杂的函数
      • 一切皆是表达式
        • 在函数式语言中,函数和数据都被看作返回值的表达式
        • 函数式语言是由表达式构成的。如果对表达式进行求值,就会返回值
          • 惰性求值
      • 惰性求值
        • 无限流:无穷数据结构,由于惰性求值,我们可以抽象构造一个无限长集合,无限长集合中的元素并不是预置进去的,而是在需要的时候才计算出来的。这让我们可以把很多问题抽象化,然后在更高的层面上解决它们
        • Optional
      • 函数组合
        • 部分应用函数(Partially Applied Functions):固定部分的参数,返回一个更少参数的函数
        • 柯里化(Currying):将一个多参函数,转换成一个依次接收单个参的函数(柯里化是为了规范统一函数参数,更好得适配函数组合)
          // f(a, b, c) => f(a)(b)(c)
          function curry(func) {
              return function inner(...args){
                  if(args.length >= func.length){
                      return func.apply(this, args)
                  } else {
                      return function(...args2){
                          return inner.apply(this, args.concat(args2))
                      }
                  }
              }
          }
          
          function sum(a, b) {
              return a + b
          }
          
          let currySum = curry(sum)
          
          console.log('currySum(1)(2)', currySum(1)(2))
          console.log('currySum(1, 2)', currySum(1, 2))
          
        • 组合(Compose):从右往左执行函数列表,按照类似 f(g(x)) 的传参执行顺序来排列的
          // compose
          function compose(...fns) {
            return fns.reduce((fn1, fn2) => (...args) => fn2(fn1(...args)))
          }
          
          const add10 = x => x + 10
          const mul10 = x => x * 10
          const add100 = x => x + 100
          
          // (10 + 100) * 10 + 10 = 1110
          compose(add10, mul10, add100)(10)
          
        • 管道(Pipeline):从左往右执行函数列表
          const pipe =
            (...fns) =>
            (value) =>
              fns.reduce((v, fn) => fn(v), value);
          
        • reducer: 最主要的作用其实是解决在使用多个 map、filter、reduce 操作大型数组时,可能会发生的性能问题
      • 代数数据类型
        • Functor 函子是实现了 map 函数的数据结构,这个 map 函数允许对容器内的元素应用一个函数,并返回一个新的容器
        class Functor {
          constructor(val) { 
            this.val = val; 
          }
        
          map(f) {
            return new Functor(f(this.val));
          }
        }
        
        • Monad(单子)
          • bind:有一个 bind函数可以转换任何函数,使其接受与返回相同的类型,从而使其可组合
          • unit:有一个 unit 函数将值包装为可组合函数接受的类型
          • Monad 对 IO 操作
            • 对副作用封装、隔离
            • 链式顺序组合:输入与输出有时候是不定的、不具体的;而函数式编程不像命令式编程那样关注执行步骤

参考

其他文章
交流区
加载中...