函數語言程式設計之Compose

JS每日一題發表於2017-09-15

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 !複製程式碼

pointfree 模式

pointfree模式指的是,永遠不必說出你的資料,它的意思是指函式無須提及將要操作的資料是什麼樣的,一等公民的函式,curry 以及compose 協作起來非常有助於實現這種模式

// 非 pointfree, 因為提到了資料 word
let snakeCase = (word) => word.toUpperCase().replace(/\s+/ig,'-');
// pointfree
let snakeCase = compose(replace(/\s+/ig,'-'),toUpperCase)複製程式碼

pointfree 模式能夠幫助我們減少不必要的命名,讓程式碼保持簡潔和通用。對函式式程式碼來說,pointfree 是非常好的石蕊試驗,因為它能告訴我們一個函式是否是接受輸入返回輸出的小函式。

一些問題

回到樓上,我們可以看到上面的compose示例都只是傳入了兩個函式,因為我們的compose實現也只支援兩個函式,那麼如果我們想要支援一條很長很長的管道的時候,顯然上面的compose就不夠用了,下面我們可以來看看redux是如何實現compose的

// 摘自 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)))
}複製程式碼

程式碼很簡潔,利用了陣列的reduce方法來處理,就這樣, 想拼多長就多長

相關文章