若要以 Function Pipeline 處理 Resolved,可使用多個 map
,如同 Promise 可使用多個 then
。
map
import { create, env } from 'sanctuary'
import { resolve, fork, map, mapRej } 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 = resolve (1)
pipe ([
map (x => x + 1),
mapRej (x => -x),
fork (error) (log)
]) (data)
data
為 Resolved,儘管在 pipe
中同時有處理 Resolved 的 map
,亦有處理 Rejected 的 mapRej
,整個 Function Pipeline 會無視 mapRej
,只執行 map
。
map :: Functor m => (a -> b) -> m a -> m b
將 Resolved 與一般 function 綁定並回傳新 Resolved
a -> b
:一般 function
m a
:data 為 Functor
m b
:回傳新 Functor
Future 亦為 Functor,所以也可使用
map
import { create, env } from 'sanctuary'
import { resolve, fork, mapRej } from 'fluture'
import { env as flutureEnv } from 'fluture-sanctuary-types'
import { error, log } from 'wink-fp'
let { pipe, map } = create ({ checkTypes: true, env: env.concat (flutureEnv) })
let data = resolve (1)
pipe ([
map (x => x + 1),
mapRej (x => -x),
fork (error) (log)
]) (data)
亦可使用 Sanctuary 的 map
,因為 Sanctuary 與 Fluture 皆支援 Fantasy Land 的 Functor。
Function Pipeline
import { create, env } from 'sanctuary'
import { resolve, fork, map, mapRej } 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 = resolve (1)
pipe ([
map (x => x + 1),
map (x => x + 2),
mapRej (x => -x),
fork (error) (log)
]) (data)
map
最可貴的是回傳 Resolved,這讓 Resolved 也能使用多個 map
完成 Function Pipeline,如同 Promise 使用多個 then
一樣。
Point-free
import { create, env } from 'sanctuary'
import { resolve, fork, map, mapRej } from 'fluture'
import { env as flutureEnv } from 'fluture-sanctuary-types'
import { error, log } from 'wink-fp'
let { pipe, add, negate } = create ({ checkTypes: true, env: env.concat (flutureEnv) })
let data = resolve (1)
pipe ([
map (add (1)),
map (add (2)),
mapRej (negate),
fork (error) (log)
]) (data)
map
與 mapRej
的 callback 可傳入 add
與 negate
使其 Point-free。
Composition Law
import { create, env } from 'sanctuary'
import { resolve, fork, map, mapRej } from 'fluture'
import { env as flutureEnv } from 'fluture-sanctuary-types'
import { error, log } from 'wink-fp'
let { pipe, add, negate } = create ({ checkTypes: true, env: env.concat (flutureEnv) })
let data = resolve (1)
let t = pipe ([
add (1),
add (2)
])
pipe ([
map (t),
mapRej (negate),
fork (error) (log)
]) (data)
Future 也是 Functor,因此支援 composition law,可將 map
的 callback 都以 pipe
組合成 t
再一次傳入 map
。
Railway Oriented Programming
map
支援 Railway Oriented Programming,因為傳入一般 function,回傳仍然是 Resolved,因此繼續留在 Resolved Track,不會切到 Rejected Track。
Conclusion
- 亦可使用 Sanctuary 的
map
取代 Fluture 的map
,因為 Sanctuary 與 Fluture 都支援 Functor - 若要使用 Sanctuary 的
map
,會出現 type checking 錯誤,因為 Sanctuary 不認識 Future,可取消 type checking,或者加入 Future 為 Sanctuary 定義的fluture-sanctuary-types
使其認識 Future
Reference
Aldwin Vlasbolm, Functional Alternative to Promises
Fluture, map