Fluture 也提供 ap
,是以 Function 為主體,跟 Sanctuary 以 Data 為主體的考量不太一樣,其 Type Signature 剛好相反。
Version
Fluture 14.0.0
ap
import { create, env } from 'sanctuary'
import { resolve, fork, ap } from 'fluture'
import { env as flutureEnv } from 'fluture-sanctuary-types'
import { log, error } from 'wink-fp'
let { pipe, add } = create ({ checkTypes: true, env: env.concat (flutureEnv) })
let data1 = resolve (1)
let data2 = resolve (2)
let add_ = resolve (add)
pipe ([
ap (data1),
ap (data2),
fork (error) (log)
]) (add_)
add_
為包進 Future 的 binary function,將 function 傳進 ap
後,可不斷地呼叫 ap
將 Future 補齊後執行 function。
Future 的 ap
最後一個 argument 為包進 Future 的 function。
ap :: Apply m => m a -> m (a -> b) -> m b
陸續提供 Future 將回傳 Future 的 Function 綁定
m a
:data 為 Applym (a -> b)
:包進 Apply 的 functionm b
:回傳新 Apply
reject
import { create, env } from 'sanctuary'
import { resolve, reject, fork, ap } from 'fluture'
import { env as flutureEnv } from 'fluture-sanctuary-types'
import { log, error } from 'wink-fp'
let { pipe, add } = create ({ checkTypes: true, env: env.concat (flutureEnv) })
let data1 = resolve (1)
let data2 = reject (2)
let add_ = resolve (add)
pipe ([
ap (data1),
ap (data2),
fork (error) (log)
]) (add_)
第 8 行
let data1 = resolve (1)
let data2 = reject (2)
data1
與 data2
都是 Future,但 data1
為 Resolved,而 data2
為 Rejected。
13 行
pipe ([
ap (data1),
ap (data2),
fork (error) (log)
]) (add_)
用法完全相同,但結果會是 Rejected。
Sanctuary
import { create, env } from 'sanctuary'
import { resolve, fork } from 'fluture'
import { env as flutureEnv } from 'fluture-sanctuary-types'
import { log, error } from 'wink-fp'
let { pipe, ap, add } = create ({ checkTypes: true, env: env.concat (flutureEnv) })
let add_ = resolve (add (1))
let data = resolve (1)
pipe ([
ap (add_),
fork (error) (log)
]) (data)
Sanctuary 也有 ap
,但其最後一個 argument 為 Future,第一個 argument 才是包進 Future 的 function,也就是 Sanctuary 與 Future 的 ap
的 type signature 剛好相反。
Apply f => f (a -> b) -> f a -> f b
將 Apply 與包進 Apply 的 function 綁定並回傳新 Apply
在 Consider flipping the argument order of ap#645 中,Future 的原作者 Aldwin Viasblom 與 Sanctuary 原作者 David Chambers 也曾討論過此問題,事實上 Sanctuary 的 ap
與 Fantasy Land 的 type signature 剛好相反,Future 與 Ramda 的 ap
才是遵循 Fantasy Land。
但 Fantasy Land 的 ap
又與 Haskell、F# 的 ap
相反,所以 Sanctuary 的堅持也是有它的道理。
只能說 Sanctuary 的 ap
對 data 較友善,而 Future 與 Fantasy Land 的 ap
對 function 較友善,各有其優點,ap
也是唯一 Sanctuary 沒有遵循 Fantasy Land 的 function。
flip
import { create, env } from 'sanctuary'
import { resolve, fork, ap } from 'fluture'
import { env as flutureEnv } from 'fluture-sanctuary-types'
import { log, error } from 'wink-fp'
let { pipe, flip, add } = create ({ checkTypes: true, env: env.concat (flutureEnv) })
let add_ = resolve (add (1))
let data = resolve (1)
pipe ([
flip (ap) (add_),
fork (error) (log)
]) (data)
12 行
pipe ([
flip (ap) (add_),
fork (error) (log)
]) (data)
若要使用 Future 的 ap
實現 Sanctuary 的 ap
也不難,只要將其 flip
即可。
Conclusion
- Fluture 的
ap
與 Sanctuary 的ap
功能完全一樣,也都支持 Apply,唯兩者 type signature 剛好相反,Fluture 的flip (ap)
剛好等於 Sanctuary 的ap
- 事實上 Fluture 的
ap
才是真正支援 Fantasy Land,但 Sanctuary 的ap
則與 F# 與 Haskell 相同
Reference
Fluture, ap
Sanctuary, Consider flipping the argument order of ap#645