點燈坊

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

使用 iif() 讓 Function Pipeline 不中斷

Sam Xiao's Avatar 2020-08-24

if else 在 Imperative 視為理所當然,但在 FP 卻是中斷 Function Pipeline 殺手,常常 Function 無法組合都是因為 if else 介入,透過 Wink-fp 的 iif(),可使 Function Pipeline 不中斷。

Version

macOS Catalina 10.15.6
Wink-fp 1.20.81

Imperative

let f = n => {
  if (n !== 1) return false
  return 100
}

f(1) // ?
f(2) // ?

實務上常需要對 argument 進行判斷,若不符合條件則使用 guard clause 提早 return false,符合條件則繼續。

iif000

&& Operator

let f = arg => (arg === 1) && 100

f(1) // ?
f(2) // ?

也可藉由 && 對 truthy value 特性完成。

iif001

Functional

import { pipe, always, equals } from 'ramda'

let iif = f => arg => arg && f()

let f = pipe(
  equals(1),
  iif(always(100))
)

f(1) // ?
f(2) // ?

&& 畢竟是 operator 無法 Function Pipeline,可將 &&iif() 實現,為了方便 point-free,將 data 放在最後一個 argument。

如此在 pipe() 時,iif() 就能接受前一個 function 傳來的值,而不需要變數。

if002

Wink-fp

import { pipe, always, equals } from 'ramda'
import { iif } from 'wink-fp'

let f = pipe(
  equals(1),
  iif(always(100))
)

f(1) // ?
f(2) // ?

Wink-fp 已經內建 iif() 可直接使用。

iif()
(a -> a) -> Boolean -> a
若 data 為 true,則執行 callback 並回傳其值

(a -> a):要執行的 function

Boolean:data 為 Boolean

a:回傳執行結果

iif() 本質為 && operator 的 function 封裝

iif003

Conclusion

  • Operator 乍看之下很討喜,其實都是中斷 Function Pipeline 殺手,因為 operator 必定要搭配變數,但 Function Pipeline 是不用變數的,因此可自行將這些 operator 包成 function,這就是 iif() 目的
  • iif() 似乎與 Ramda 的 when() 很類似,when() 必須接受兩個 function,而 iif() 只需接受一個 function,且 iif() 會自動轉型成 truthy value 或 falsy value,when() 必須明確轉型

Reference

Ramda, when()