點燈坊

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

使用 chainRej 將 Rejected 與回傳 Future 的 Function 綁定

Sam Xiao's Avatar 2021-07-22

mapRejchainRej 都可處理 Rejected,唯傳入 mapRej 為一般 Function,而傳入 chainRej 為回傳 Future 的 Function。

Version

Fluture 14.0.0

chainRej

import { create, env } from 'sanctuary'
import { reject, resolve, fork, map, mapRej, chainRej } from 'fluture'
import { env as flutureEnv } from 'fluture-sanctuary-types'
import { error, log } from 'wink-fp'

let { pipe } = create ({ checkTypes: true, env: env.concat (flutureEnv) })

let data = reject (1)

pipe ([
  map (x => x + 1),
  mapRej (x => x + 2),
  chainRej (x => reject (x + 3)),
  fork (error) (log)
]) (data) 

data 為 Rejected,儘管在 pipe 中同時有處理 Resolved 的 map,亦有處理 Rejected 的 mapRej,整個 Function Pipeline 會無視 map,只執行 mapRejchainRej

data 為 Rejected,在 pipe 同時有 mapmapRejchainRej

  • map:只處理 Resolved
  • mapRej:只處理 Rejected,傳入普通 function
  • chainRej:只處理 Rejected,傳入回傳 Future 的 function,若回傳 Rejected 則繼續 Rejected Track;若回傳 Resolved 則回到 Resolved Track

chainRej :: (a -> Future c b) -> Future a b -> Future c b
將 Rejected 與回傳 Future 的 function 綁定並回傳新 Future

a -> Future c b:回傳 Future 的 function

Future a b:data 為 Future

Future c b:回傳新 Future

chainRej 為 Future 專屬 function,因此只支援 Future,不像 chain 是支援 Functor

chainrej000

Function Pipeline

import { create, env } from 'sanctuary'
import { reject, resolve, fork, map, mapRej, chainRej } from 'fluture'
import { env as flutureEnv } from 'fluture-sanctuary-types'
import { error, log } from 'wink-fp'

let { pipe } = create ({ checkTypes: true, env: env.concat (flutureEnv) })

let data = reject (1)

pipe ([
  map (x => x + 1),
  mapRej (x => x + 2),
  chainRej (x => reject (x + 3)),
  chainRej (x => reject (-x)),
  fork (error) (log)
]) (data) 

chainRej 最可貴的是若回傳 Rejected,可使用多個 chainRej 完成 Function Pipeline。

Ramda 的 otherwise 會回傳 Resolved,這使得整個 Function Pipeline 中只能使用一個 otherwise,若要使用 Function Pipline 處理 Rejected,只能另外抽 function 再傳入 otherwise,而不能如 Future 一樣在一個 Function Pipeline 同時處理 Resolved 與 Rejected。

chainrej003

Point-free

import { create, env } from 'sanctuary'
import { reject, resolve, fork, map, mapRej, chainRej } from 'fluture'
import { env as flutureEnv } from 'fluture-sanctuary-types'
import { error, log } from 'wink-fp'

let { pipe, compose, add, negate  } = create ({ checkTypes: true, env: env.concat (flutureEnv) })

let data = reject (1)

pipe ([
  map (add (1)),
  mapRej (add (2)),
  chainRej (compose (reject) (add (3))),
  chainRej (compose (reject) (negate)),
  fork (error) (log)
]) (data) 

也可使 mapmapRejchainRej 的 callback 能 Point-free。

chainrej001

Railway Oriented Programming

chainrej002

chainRej 支援 Railway Oriented Programming,因為傳入回傳 Future 的 function,可能是 Rejected 或 Resolved,因此可能繼續在 Rejected Track,或者回到 Resolved Track。

Conclusion

  • 可在同一個 Function Pipeline 使用多次 mapRejchainRej,不像 Promise 只能使用一次 otherwise
  • chainRej 支援 Railway Oriented Programming,可繼續留在 Rejected Track,或者切回 Resolved Track

Reference

Aldwin Vlasbolm, Functional Alternative to Promises
Future, chainRej
Future, encase