點燈坊

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

使用 chain 組合回傳 Either 的 Function

Sam Xiao's Avatar 2020-11-07

Either 適合 Function Pipeline,可提早結束讓後續 Pure Function 不執行,但若 Pure Function 也回傳 Either,則會產生 Nested Either,如此必須使用 chain 取代 map

Version

Sanctuary 3.1.0

add

import { pipe, Left, Right, map, add } from 'sanctuary'

let div = x => y => 
  y === 0 ? 
  Left ('Can not divide by zero') : 
  Right (x / y)

let f = x => pipe ([
  div (x),
  map (add (1))
])

f (2) (0) // ?
f (2) (1) // ?
f (3) (1) // ?

第 8 行

let f = x => pipe ([
  div (x),
  map (add (1))
])

div 回傳 Either,但 add 只是回傳 Number,此時簡單使用 map 組合 add 即可。

chain000

Either

import { pipe, map, Left, Right } from 'sanctuary'

let div = x => y => 
  y === 0 ? 
  Left ('Can not divide by zero') : 
  Right (x / y)

let add = x => y =>
  y === 2 ?
  Left ('Can not add by 2') :
  Right (x + y)  

let f = x => pipe([
  div (x),
  map (add (1))
])

f (2) (0) // ?
f (2) (1) // ?
f (3) (1) // ?

第 8 行

let add = x => y =>
  y === 2 ?
  Left ('Can not add by 2') :
  Right (x + y) 

沒有使用 Sanctuary 提供的 add,自行實作回傳 Either 的 add

此特殊版本的 add 無法處理 +2 會發出 Exception,因此改回傳 Either。

13 行

let f = x => pipe([
  div (x),
  map (add (1))
])

一樣使用 map 組合 add

chain001

當改用回傳 Either 的 add 時,會發現結果出現 Nested Either,這並不是我們想要的。

chain

import { pipe, Left, Right, chain } from 'sanctuary'

let div = x => y => 
  y === 0 ? 
  Left ('Can not divide by zero') : 
  Right (x / y)

let add = x => y =>
  y === 2 ?
  Left ('Can not add by 2') :
  Right (x + y)  

let f = x => pipe ([
  div (x),
  chain (add (1))
])

f (2) (0) // ?
f (2) (1) // ?
f (3) (1) // ?

13 行

let f = x => pipe ([
  div (x),
  chain (add (1))
])

map 改成 chain

chain002

map 改成 chain 後,就不會出現 Nested Either。

Either Chain

import { pipe, Left, Right, map, chain } from 'sanctuary'

let div = x => y => 
  y === 0 ? 
  Left ('Can not divide by zero') : 
  Right (x / y)

let add = x => y =>
  y === 2 ?
  Left ('Can not add by 2') :
  Right (x + y)

let mul = x => y =>
  y === 4 ?
  Left ('Can not multiply by 4') :
  Right (x * y)  

let f = x => pipe([
  div (x),
  chain (add (1)),
  chain (mul (2)),
])

f (2) (0) // ?
f (2) (1) // ?
f (3) (1) // ?
f (4) (1) // ?

13 行

let mul = x => y =>
  y === 4 ?
  Left ('Can not multiply by 4') :
  Right (x * y)

也自行實作回傳 Either 的 mul,此版本無法處理 *4 會發出 Exception。

18 行

let f = x => pipe([
  div (x),
  chain (add (1)),
  chain (mul (2)),
])

遇到會回傳的 Either 的 function,只要由 map 改用 chain 即可。

chain003

Conclusion

  • 若要組合一般 function,使用 map 即可;若要組合回傳 Either 的 function,則要使用 chain

Reference

Sanctuary, Either