點燈坊

學而時習之,不亦悅乎

使用 useWith() 組合 Function

Sam Xiao's Avatar 2019-08-08

一談到 Function Composition,直覺都會想到 pipe()compose(),事實上就廣義而言,別忘了 useWith() 也算是。

Version

macOS Mojave 10.14.5
VS Code 1.35.0
Quokka 1.0.224
Ramda 0.26.1

Imperative

let fn = arg => (arg + 1) * 2;

fn(2); // ?

+ 1* 2,若使用 imperative,就會使用 operator。

usewith000

Functional

import { add, multiply } from 'ramda';

let fn = arg => multiply(2, add(1, arg));

fn(2); // ?

若使用 FP,就不會使用 operator 了,全部改用 function。

usewith001

pipe()

import { add, multiply, pipe } from 'ramda';

let fn = pipe(
  add(1),
  multiply(2)
);

fn(2); // ?

以 dataflow 角度,arg 是先執行 add(1),再將結果傳給 multiply(2) 執行,因此可用 pipe() 加以組合,還順便 point-free。

pipe()
(((a, b, …, n) → o), (o → p), …, (x → y), (y → z)) → ((a, b, …, n) → z)
將 function 由左至右,依據 dataflow 方向組合

usewith002

compose()

import { add, multiply, compose } from 'ramda';

let fn = compose(
  multiply(2),
  add(1)
);

fn(2); // ?

由另外一個角度思考:fn() 其實是 add(1)multiply(2) 兩個 funciton 組合而成,因此可使用 compose() 加以組合,還順便 point-free。

compose()
((y → z), (x → y), …, (o → p), ((a, b, …, n) → o)) → ((a, b, …, n) → z)
將 function 由右至左,依據 function 撰寫方向組合

usewith003

map()

import { add, multiply, map } from 'ramda';

let fn = map(
  multiply(2),
  add(1)
);

fn(2); // ?

若只 compose() 兩個 function,可等價使用 map() 替換,因為 function 也是 Functor,將一個 function 透過 projection function 轉換,等效於兩個 function 去 compose。

map()
Functor f => (a → b) → f a → f b
將 Functor a 轉換成 Functor b

useWith005

useWith()

import { add, multiply, useWith } from 'ramda';

let fn = useWith(
  multiply(2), [add(1)]
);

console.log(fn(2));

再由另外一個叫度去思考:multiply(2) 才是最終要執行的 main function,add(1) 只是處理 argument 的 transformer function,因此可使用 useWith() 加以組合,還順便 point-free。

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

Conclusion

  • FP 與數學一樣,本來就不是單一方法解題,所以存在不同 function 組合方式
  • useWith() 一般都用在多 argument,若退化成單一 argument,其實等效於 pipe()compose()

Peference

Ramda, pipe()
Ramda, compose()
Ramda, map()
Ramda, useWith()
Ramda, add()
Ramda, multiply()