函數式編程-compose與pipe


函數式編程中有一種模式是通過組合多個函數的功能來實現一個組合函數。一般支持函數式編程的工具庫都實現了這種模式,這種模式一般被稱作compose與pipe。以函數式著稱的Ramda工具庫為例。

const R = require('ramda');
function inc (num) {
  return ++num;
}
const fun1 = R.compose(Math.abs, inc, Math.pow)
const fun2 = R.pipe(Math.pow, Math.abs, inc)
console.log(fun1(-2, 3)) // 7
console.log(fun2(-2, 3)) // 9

從上面的例子可以看出,假設fgh分別表示三個函數,則compose(f,g,h)返回的函數完成類似(...args) => f(g(h(...args)))的功能。即從右到左組合多個函數,前面函數的返回值作為下一個函數的參數;pipe(f,g,h)返回的函數完成類似(...args) => h(g(f(...args)))的功能,即從左到右組合多個函數,前面函數的返回值作為下一個函數的參數;預計最先執行的函數可以接受任意個參數,后面的函數預計只接受一個參數。把compose放在前面講是因為其更加體現了數學含義上的從右到左的操作。
redux中即有使compose函數的應用來增強store

import { createStore, applyMiddleware, compose } from 'redux'
import thunk from 'redux-thunk'
import DevTools from './containers/DevTools'
import reducer from '../reducers'
const store = createStore(
  reducer,
  compose(
    applyMiddleware(thunk),
    DevTools.instrument()
  )
)

總的來說,composepipe函數接收函數序列,並返回一個函數,使用數組的reduce方法可以很容易實現這兩個函數,下面是redux源碼中對compose方法的實現:

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)))
}

上面的代碼是ES6+的實現方式,仿照上面的代碼很容易寫出ES5的實現方法

function _compose(f, g) {
  return function() {
    return f.call(this, g.apply(this, arguments));
  };
}

function compose() {
  var args = Array.prototype.slice.call(arguments)
  if (args.length === 0) {
    return function(arg){
      return arg
    }
  }
  if (args.length === 1) {
    return args[0]
  }
  return args.reduce(_compose)
}

實現了compose方法,只需要改動很少的地方就能實現pipe方法。

function pipe(...funcs) {
  if (funcs.length === 0) {
    return arg => arg
  }

  if (funcs.length === 1) {
    return funcs[0]
  }

  return funcs.reduce((a, b) => (...args) => b(a(...args)))
}

或者直接借助compose方法實現pipe

function pipe(...funcs){
  if(funcs.length === 0) {
    return arg => arg
  }
  return compose(...funcs.reverse())
}

組合的概念來自於數學,其有一個重要的特性就是結合律

// 結合律(associativity)
var associative = compose(f, compose(g, h)) == compose(compose(f , g), h); // true

符合結合律意味着不管你是把gh分到一組,還是把fg分到一組都不重要。在實際開發過程中,我們可以盡可能的最小化函數的功能,這也符合單一原則,然后通過結合以及組合來完成較大的功能需求。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM