if else
在每個程式語言都有,但這是 Imperative 使用方式,會使得 Function Pipeline 中斷,事實上可使用 Function 加以重構。
Version
macOS Catalina 10.15.6
Ramda 0.27.0
Wink-fp 1.20.85
if
let data = 'Sam'
let f = x => {
if (x) return 'not empty'
}
f(data) // ?
很典型 if
,若 data
有值才印出 not empty
。
&&
let data = 'Sam'
let f = x => x && 'not empty'
f(data) // ?
ECMAScript 的獨門武器,使用 &&
可使 code 更精簡。
when()
import { pipe, when, always } from 'ramda'
import { bool } from 'wink-fp'
let data = 'Sam'
let logNotEmpty = always('not empty')
let f = pipe(
when(bool, logNotEmpty)
)
f(data) // ?
將
not empty
部分抽出獨立的logNotEmpty()
使用
when()
取代if
,但when()
並沒有 falsy value 概念,因此需使用bool()
明確將 String 轉成 Boolean
使用
when()
最大優點是可以整合在 Function Pipeline 內,這是if
所辦不到的
isNonEmpty()
import { pipe, when, always } from 'ramda'
import { isNonEmpty } from 'wink-fp'
let data = 'Sam'
let logNotEmpty = always('not empty')
let f = pipe(
when(isNonEmpty, logNotEmpty)
)
f(data) // ?
由於 when()
第一個 argument 接受 function,因此對於 input 有加工的空間,除了使用 bool()
外,也能更明確使用 isNonEmpty()
使語意更為清楚。
identity()
import { pipe, when, always, identity } from 'ramda'
let data = true
let logTrue = always('true')
let f = pipe(
when(identity, logTrue)
)
f(data) // ?
若 data
已經是 Boolean,就不必靠 when()
的第一個 function 作轉換,此時可使用 identity()
維持不變。
iif()
import { pipe, always } from 'ramda'
import { iif } from 'wink-fp'
let data = 'Sam'
let logNotEmpty = always('not empty')
let f = pipe(
iif(logNotEmpty)
)
f(data) // ?
也可使用 Wink-fp 的 iif()
,它與 Ramda 的 when()
有以下差別:
iif()
底層為&&
,可接受 falsy value,而when()
不行iif()
不需要其他 function 轉換或identity()
,只接受 callback
若 data 需經過 function 處理則使用
when()
,若可轉為 truthy value 或 falsy value 則使用iif()
if not
let data = ''
let f = x => {
if (!x) return 'empty'
}
f(data) // ?
很典型 if not
,若 data
為 empty string 有值才印出 empty
。
||
let data = ''
let f = x => x || 'empty'
f(data) // ?
ECMAScript 的獨門武器,使用 ||
可使 code 更精簡。
unless()
import { pipe, unless, always } from 'ramda'
import { bool } from 'wink-fp'
let data = ''
let logEmpty = always('empty')
let f = pipe(
unless(bool, logEmpty)
)
f(data) // ?
- 將
empty
部分抽出獨立的logEmpty()
- 使用
unless()
取代if not
,但unless()
並沒有 falsy value 概念,因此需使用bool()
明確將 String 轉成 Boolean
使用
unless()
最大優點是可以整合在 Function Pipeline 內,這是if not
所辦不到的
isNonEmpty()
import { pipe, unless, always } from 'ramda'
import { isNonEmpty } from 'wink-fp'
let data = ''
let logEmpty = always('empty')
let f = pipe(
unless(isNonEmpty, logEmpty)
)
f(data) // ?
由於 unless()
第一個 argument 接受 function,因此對於 input 有加工的空間,除了使用 bool()
外,也能更明確使用 isNonEmpty()
。
isEmpty()
import { pipe, when, isEmpty, always } from 'ramda'
let data = ''
let logEmpty = always('empty')
let f = pipe(
when(isEmpty, logEmpty)
)
f(data) // ?
unless(isNotEmpty)
這種兩次反向邏輯很繞口,改用 when(isEmpty)
語意更好。
identity()
import { pipe, unless, identity, always } from 'ramda'
import { bool } from 'wink-fp'
let data = false
let logEmpty = always('empty')
let f = pipe(
unless(identity, logEmpty)
)
f(data) // ?
若 data
已經是 Boolean,就不必靠 unless()
的第一個 function 作轉換,此時可使用 identity()
維持不變。
nif()
import { pipe, always } from 'ramda'
import { nif } from 'wink-fp'
let data = ''
let logEmpty = always('empty')
let f = pipe(
nif(logEmpty)
)
f(data) // ?
也可使用 Wink-fp 的 nif()
,他與 Ramda 的 unless()
有以下差別:
iif()
底層為||
,可接受 falsy value,而unless()
不行nif()
不需要其他 function 轉換或identity()
,只接受 callback
若 data 需經過 function 處理則使用
unless()
,若可轉為 truthy value 或 falsy value 則使用nif()
if else
let data = 'Sam'
let f = x => {
if (data) return 'non empty'
else return 'empty'
}
f(data) // ?
很典型 if else
,若 data
有值回傳 not empty
,否則回傳 empty
。
?:
let data = 'Sam'
let f = x => x ? 'non empty' : 'empty'
f(data) // ?
也可使用 ?:
ternary operator 使用 code 更精簡。
ifElse()
import { pipe, ifElse, isEmpty, always } from 'ramda'
import { isNonEmpty } from 'wink-fp'
let data = 'Sam'
let logEmpty = always('empty')
let logNotEmpty = always('not empty')
let f = pipe(
ifElse(isNonEmpty, logNotEmpty, logEmpty)
)
f(data) // ?
- 將
empty
與not empty
部分抽出獨立的logEmpty()
與logNotEmpty()
- 使用
ifElse()
取代if else
,但ifElse()
並沒有 falsy value 概念,因此需使用isNonEmpty()
明確回傳 Boolean
使用
ifElse()
最大優點是可以整合在 Function Pipeline 內,這是if not
所辦不到的
identity()
import { pipe, ifElse, identity, always } from 'ramda'
let data = true
let logTrue = always('true')
let logFalse = always('false')
let f = pipe(
ifElse(identity, logTrue, logFalse)
)
f(data) // ?
若 data
已經是 Boolean,就不必靠 ifElse()
的第一個 function 作轉換,此時可使用 identity()
維持不變。
either()
import { pipe, either } from 'ramda'
let data = 'Sam'
let logEmpty = () => 'empty'
let logNotEmpty = () => 'not empty'
let f = pipe(
either(logNotEmpty)(logEmpty)
)
f(data) // ?
也可使用 either()
,它與 ifElse()
有以下差別:
either()
可接受 falsy value,而ifElse()
不行either()
不需要其他 function 轉換或identity()
,只接受 function 即可
若 data 需經過 function 處理則使用
ifElse()
,若可轉為 truthy value 或 falsy value 則使用either()
Conclusion
很多人覺得 FP 只能用於處理 Array,事實上邏輯也能用 FP 處理
if else
與 operator 其實都非 FP 產物,應盡量避免,而改用相對應 function 取代