Monad 必須實現 Functor、Apply、Applicative 與 Chain,其中學習 Chain 是必經過程。
Version
Fantasy Land 5.0.0
Fantasy Land
Chain 基於 Apply 與 Functor,也就是 Apply 與 Functor 所有特性 Chain 皆具備。
Chain
import { compose, map, ap, chain, inc } from 'ramda'
let Chain = x => {
let _x = x
let map = f => Chain (f (_x))
let ap = x => x.map (f => f (_x))
let chain = f => f (_x)
let getValue = _ => _x
return {
map,
ap,
chain,
getValue
}
}
let getValue = x => x.getValue ()
let data = Chain (1)
let inc_ = Chain (inc)
let inc__ = compose (Chain, inc)
compose (getValue, map (inc)) (data) // ?
compose (getValue, ap (data)) (inc_) // ?
compose (getValue, chain (inc__)) (data) // ?
實現 Chain 需滿足 3 個 typeclass:
- Functor:實現
map
將 Functor 與 function 綁定 - Apply:實現
ap
將 Apply 與包進 Apply 的 function 綁定 - Chain:實現
chain
將 Chain 與回傳 Chain 的 function 綁定
第 4 行
let _x = x
相當於 constructor 將 x
值存進 _x
內。
第 6 行
let map = f => Chain (f (_x))
Chain 必須實現 Functor。
根據 Fantasy Land 定義:
fantasy-land/map :: Functor f => f a ~> (a → b) → f a → f b
Object 必須有 map
才是 Functor。
將 Object 內部 _x
透過傳入 f
運算後,使用 Chain
包成新 Chain 回傳。
第 8 行
let ap = x => x.map (f => f (_x))
Chain 必須實現 Apply。
根據 Fantasy Land 定義:
fantasy-land/ap :: Apply f => f a ~> f (a -> b) -> f b
Object 必須有 ap
才是 Apply。
從傳入 Chain 取出 f
後,將 Object 內部 _x
傳入 f
運算後,改變 Chain 回傳。
由於
ap
需呼叫map
取得f
,因此 Apply 必須先實現 Functor 的map
10 行
let chain = f => f (_x)
根據 Fantasy Land 定義:
fantasy-land/chain :: Chain m => m a ~> (a -> m b) -> m b
Object 必須有 chain
才是 Chain。
將傳入回傳 Chain 的 function 套用 Object 內部 value 回傳。
13 行
let getValue = _ => _x
使用 getValue
取出 Chain 內部 value。
getValue
並非 Fantasy Land 所要求,只是方便取出 Object 內部 value
22 行
let getValue = x => x.getValue ()
提供 free function 方便使用:
getValue
:呼叫 Chain 的getValue
24 行
let data = Chain (1)
let inc_ = Chain (inc)
let inc__ = compose (Chain, inc)
data
為 Chaininc_
:將inc
包進 Chaininc__
:inc
回傳 Chain
28 行
compose (getValue, map (inc)) (data) // ?
compose (getValue, ap (data)) (inc_) // ?
compose (getValue, chain (inc__)) (data) // ?
- 使用 Ramda 的
map
將 Chain 與inc
綁定,確認自行建立的 Chain 符合 Fantasy Land 規格 - 使用 Ramda 的
ap
將Apply
與包進 Chain 的 function 綁定,確認自行建立的 Chain 符合 Fantasy Land 規格 - 使用 Ramda 的
chain
將 Chain 與回傳 Chain 的 function 綁定,確認自行建立的 Chain 符合 Fantasy Land 規格
Conclusion
- Chain 必須實現 Apply 與 Functor,所以也必須實現
ap
與map