pipe()
是 FP 最重要 Function 之一,其中 Function Pipeline 就是由 pipe()
展開,實務上都是直接使用 Ramda 的 pipe()
,事實上也能自行以 ECMAScript 的 reduce()
實現。
Version
Ramda 0.27.0
Wink-fp 1.20.47
Ramda
import { pipe, filter, map } from 'ramda'
let data = [
{ title: 'FP in JavaScript', price: 100 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 300 }
]
let f = v => pipe(
filter(x => x.price === v),
map(x => x.title)
)
f(300)(data); // ?
實務上實現 Function Pipeline 時,會使用 Ramda 的 pipe()
。
reduce()
import { filter, map } from 'ramda'
let data = [
{ title: 'FP in JavaScript', price: 100 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 300 }
]
let pipe = (...fs) => v => fs.reduce((g, f) => f(g), v)
let f = v => pipe(
filter(x => x.price === v),
map(x => x.title),
)
f(300)(data) // ?
第 1 行
import { filter, map } from 'ramda'
沒使用 Ramda 所提供的 pipe()
。
第 9 行
let pipe = (...fs) => v => fs.reduce((g, f) => f(g), v)
由於 pipe()
是由左至右,因此使用 reduce()
。
(...fs)
使用 ES6 的 rest parameter,表示 pipe()
的 argument 個數無限,且 fs
為 array,可大膽使用 Array.prototype
下的 reduce()
。
v => fs.reduce((g, f) => f(g), v)
f
為目前 function,g
為組合後 function,每次會執行 f(g)
組合計算結果。
因為結果仍是 function,所以為 v => fns.reduce()
。
Wink-fp
import { filter, map } from 'ramda'
import { pipe } from 'wink-fp'
let data = [
{ title: 'FP in JavaScript', price: 100 },
{ title: 'RxJS in Action', price: 200 },
{ title: 'Speaking JavaScript', price: 300 }
]
let f = v => pipe(
filter(x => x.price === v),
map(x => x.title),
)
f(300)(data) // ?
亦可改用 Wink-fp 所提供的 pipe()
,結果完全相同。
pipe()
(((a, b, …, n) → o), (o → p), …, (x → y), (y → z)) → ((a, b, …, n) → z)
將 function 由左至右組合成新 function
Conclusion
pipe()
一直被認為是黑魔法,事實上只是將 function 加以reduce()
而已,能自己寫過一次,就不會覺得那麼遙不可及了
Reference
Yazeed Bzadough, 10 More Utility Functions Made with Reduce
MDN, Rest parameters
MDN, reduce()
Ramda, pipe()