Type Signature
of :: Applicative f => a -> f a
Law
v.ap(A.of(x => x)) === v
A.of(x).ap(A.of(f)) === A.of(f(x))
A.of(y).ap(u) === u.ap(A.of(f => f(y)))
Implement
Identity.of = x => Identity(x);
// Identity
Identity(1).ap(Identity.of(x => x)) === Identity(1);
// homomorphism
Identity.of(1).ap(Identity.of(add(1))) === Identity.of(add(1)(1))
// intercharge
Identity.of(1).ap(Identity.of(add(1))) === Identity(add(1)).ap(Identity(f => f(1)))
usage
想像一下在上一章 Apply 上提到的, 若一個 Monoid 是有 concat
method 功用是將值進行合併,並且有 empty
作為初始值,那 Applicative Functor 就是有 ap
method 將 Container 進行合併,並有 of
作為該Container 初始的值。
例如我們現在有一個函式 h
, 其 signature 為
h :: a -> f b -> f c
若要執行 h
函式,就需要先放入 a
跟 f b
,但很不巧的我們只有 b
此時 of
就非常有用,其將 b
包覆到其 Container。若現在有 of 這個 method 在 f
內,我們就可以透過 f.of(b)
轉換成我們所需的第二個參數 f b
再舉例來說,未來的章節裡我們一個概念 Sequence
const append = y => xs => xs.concat([y]);
const mySequence = (A, xs) => xs.reduce((acc, val) => lift2(append)(val)(acc), A.of([]))
mySequence(Identity, [Identity(1), Identity(2), Identity(3)]) // Identity([1, 2, 3])
其可以將 Container 內的值收集到同組資料結構,像是 Map
, Array
... 等,而這有什麼用呢? 未來我們會介紹到專門處理非同步的 Task Monad,而此概念就可以發揮極大的效果
sequence(Task, [Task(getUserList), Task(getCategroy)]) // Task([[...users, ...categroy]])
到目前為止,我們還沒有介紹如何將 Effect 與 Effect 進行 compose,而下一章我們將會介紹到它 Chain
f | g | composition |
---|---|---|
pure | pure | compose(f, g) |
effects | pure(unary) | f.map(g) |
effects | pure(n-ary) | f1.map(g).ap(f2) |
effects | effects | ? |
Chain
感謝大家閱讀!