點燈坊

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

使用 nif() 讓 Function Pipeline 不中斷

Sam Xiao's Avatar 2020-08-24

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

Version

macOS Catalina 10.15.6
Wink-fp 1.20.81

Imperative

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

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

實務上常需要對 argument 進行判斷,若不符合條件則回傳值, 否則回傳 true 繼續。

nif000

|| Operator

let f = n => (n === 1) || 100

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

也可藉由 || 對 falsy value 特性完成。

nif001

Functional

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

let nif = f => x => x || f()

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

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

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

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

nif002

Wink-fp

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

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

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

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

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

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

Boolean:data 為 Boolean

a:回傳執行結果

nif() 本質為 || operator 的 function 封裝

nif003

Conclusion

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

Reference

Ramda, unless()