FP 常被人詬病效率問題,若使用 pipe()
組合了 3 個 Function,由於 Pure Function 每次都回傳全新 Array,因此要執行三次 Loop,在 Array 筆數大時有明顯劣勢,透過 transduce()
只要執行一次 Loop 即可。
Version
Ramda 0.27.1
Function Pipeline
import { pipe, take, map, add } from 'ramda'
let data = [1, 2, 3]
pipe(
map(add(1)),
take(2)
)(data) // ?
- 使用
add()
對 Array 每個 element 加1
- 使用
take()
只取得前兩個 element
pipe()
組合了map()
與take()
兩個 function,會執行兩次 loop,若 Array 資料量大會明顯發現執行效率不佳
Transducer
import { compose, take, map, add, transduce, append } from 'ramda'
let data = [1, 2, 3]
let f = compose(
map(add(1)),
take(2)
)
transduce(f, (ac, x) => append(x, ac), [], data) // ?
第 5 行
let f = compose(
map(add(1)),
take(2)
)
要使用 transduce()
時,首先將原本 function 從 pipe()
改成 compose()
。
10 行
transduce(f, (ac, x) => append(x, ac), [], data) // ?
transduce()
的 signature 與 reduce()
類似,唯第一個 argument 改傳入 function,其餘 argument 都相同。
transduce()
(c → c) → ((a, b) → a) → a → [b] → a
回傳只執行一次 loop 的 function
c -> c
:由 compose()
改寫的 function
(a, b) → a
:iterator function,運算 accumulator 與 value 關係
a
:accumulator 的初始值
[b]
:data 為 array
a
:回傳為新 array
flip()
import { compose, take, map, add, transduce, flip, append } from 'ramda'
let data = [1, 2, 3]
let f = compose(
map(add(1)),
take(2),
)
transduce(f, flip(append), [], data) // ?
10 行
transduce(f, flip(append), [], data) // ?
Iterator function 的 signature 剛好跟 append()
相反,可使用 flip(append)
使其 Point-free。
Conclusion
- FP 常為人詬病執行效率不佳,透過
transduce()
可改善此問題 - 原使用
pipe()
所組合 function 須改用compose()
- Iterator function 可由
flip(append)
使其 Point-free
Reference
Jeremy Daly, Transducers: Supercharge your functional JavaScript
James Long, Transducer.js: A JavaScript Library for Transformation of Data