函数式编程之Compose

Compose基本概念

顾名思义,在函数式编程中,Compose 就是将几个有特点的函数拼凑在一起, 让它们结合, 产生一个崭新的函数,如下就是组合

const compose = (f,g) => (...arg) => f(g(...arg))

f、g都是函数,...arg是在他们之间通过管道(pipe)传输的值。

“组合函数”执行时,其内部的所有函数都会按照组合时的顺序并以队列的形式有序的执行,前一个函数的返回值会作为下一个函数的参数被接收,因此“组合函数”中的第一个执行的函数可以接收多个参数,而之后的函数只能接收一个参数(上一个函数的返回值)。像这样一个或多个指定的参数会从“组合函数”的入口函数(第一个执行的函数)中被传入,而之后则会在多个组合串联的函数管道中进行加工、传输和输出。

让我们来尝试使用一下组合

let toUpperCase = (x) => x.toUpperCase();
let exclaim = (x) => x + '!';
let shout = compose(toUpperCase,exclaim);
shout('hello world')
// HEELO WORLD !

compose实现

利用了数组的reduce方法来处理。利用了数组的 reduce 合并功能, 每次遍历合并都会将上一次组合后的函数返回回来再与当前的函数参数进行组合。依次不断的累积组合,最终返回这个组合函数。

// 摘自 https://github.com/reactjs/redux/blob/master/src/compose.js
export default function compose(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }
  if (funcs.length === 1) {
    return funcs[0]
  }
  // 从右向左执行的
  return funcs.reduce((a, b) => (...args) => a(b(...args)))
}

pipe 与 compose

pipe 函数与 compose函数的共同点是都返回“组合函数”,区别则是执行的顺序不同,前者pipe是从左向右执行,后者compose则是从右向左执行。 实现 pipe函数非常简单,只需要对 compose 函数的包裹顺序进行调整一下即可, 或者使用一下reverse方法。

function pipe(...funs) {
  if (funs.length === 0) {
    return arg => arg;
  }
  if (funs.length === 1) {
    return funs[0];
  }
  // 从左向右执行的
  return funs.reverse().reduce((a, b) => (...args) => a(b(...args)))
}

1 + 2 =

求知若飢,虛心若愚。