點燈坊

失くすものさえない今が強くなるチャンスよ

使用 useWith() 組合 Function

Sam Xiao's Avatar 2020-04-09

若 Function 的各自 Argument 先經過不同 Function 處理過,最後在傳給 Function 的各自 Argument,則可使用 useWith() 使其 Point-free。

Version

macOS Catalina 10.15.4
VS Code 1.43.2
Quokka 1.0.285
Ramda 0.27.0

Functional

import { find, propEq } from 'ramda'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 },
]

let f = v => a => find(propEq('price')(v))(a)

f(100)(data) // ?

若我們想根據 price 找資料建立了 f(),其中第一個 argument 為要搜尋的 v,第二個 argument 為 a,再使用 find()propEq() 組合。

usewith003

Point-free

import { find, propEq } from 'ramda'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 },
]

let f = v => find(propEq('price')(v))

f(100)(data); // ?

由於 a 在最後一個 argument,因此可輕易 point-free 掉 a

usewith000

Point-free

import { find, propEq, useWith, identity } from 'ramda'

let data = [
  { title: 'FP in JavaScript', price: 100 },
  { title: 'RxJS in Action', price: 200 },
  { title: 'Speaking JavaScript', price: 300 },
]

let f = useWith(
  find, [propEq('price'), identity]
)

f(100)(data) // ?

對於這種超過一個 argument 的 function,若我們想將全部 argument 都 point-free 可以使用 useWith(),他將回傳一個新的 curried function,且 argument 個數與原本 function 相同。

useWith()
((x1, x2, ...) -> z) -> [(a -> x1), (b -> x2), ...] -> (a -> b -> ... -> z)
建立一個與原 function 的 argument 個數相同的新 function,且各 argument 會先經過 transformer function 處理過再傳給原 function 執行

((x1, x2, ...) -> z):原本尚未 curried、尚未 point-free 的 function

[(a -> x1), (b -> x2), ...]:為 array,有幾個參數就會有幾個 transformer function,新 function 的所有參數,都會經過 transformer function 執行過,結果才會傳給原 function

(a -> b -> ... -> z):回傳新 function,且是 curried function

usewith002

let f = x => a => find(propEq('price')(x))(arr)

let f = useWith(
  find, [propEq('price'), identity]
)

要將 f() 重構成 point-free 很簡單:

  1. find() 放在 useWith() 的第一個 argument
  2. 將原本 在 find() 第二個 argument 的 propEq('price') 改寫在 array 內
  3. v 不變則使用 identity()

如此 va 兩個 argument 就被幹掉了,成了全部 point-free。

usewith001

Conclusion

  • 若要使用 useWith() 時,建議先還原之前 point-free 掉的 data argument,連其他 argument 與 data argument 一起思考如何 point-free

Reference

Ramda, find()
Ramda, useWith()
Ramda, identity()