當引入 Maybe 後,若使用 map
將 Array 與回傳 Maybe 的 Function 綁定,則會產生 Array Maybe,此時我們很難從 Maybe 取出內部 Value,可使用 traverse
將 Array Maybe 轉成 Maybe Array,如此就很容易從 Maybe 取出 Value。
Version
Sanctuary 3.1.0
map
import { map, parseInt } from 'sanctuary'
let data = ['a', 'b', 'c']
map (parseInt (16)) (data) // ?
data
為 Array,想將 Char 轉成 Integer。
因為 parseInt
回傳 Maybe,透過 map
綁定後回傳 Array Maybe,我們很難從 Array Maybe 取出 Maybe 內部 value。
traverse
import { pipe, map, Maybe, parseInt, traverse, I, maybe } from 'sanctuary'
let data = ['a', 'b', 'c']
pipe ([
map (parseInt (16)),
traverse (Maybe) (I),
maybe ([]) (I)
]) (data) // ?
使用 pipe
組合 IIFE:
map (parseInt (16))
:每個 element 都套用parseInt (16)
,回傳 Array Maybetraverse (Maybe) (I)
:將 Array Maybe 轉成 Maybe Array,但每個 element 都套用I
不變maybe ([]) (I)
:從 Maybe 取出內部 value,若為 Nothing 則回傳 Empty Array
traverse :: (Applicative f, Traversable t) => TypeRef f -> (a -> f b) -> t a -> f (t b)
將 Traversable Applicative 轉成 Applicative Traversable
TypeRef f
:最後結果型別,須為 Applicative(a -> f b)
:回傳 Applicative 的 function,每個 element 都會套用t a
:data 為 Traversablef (t b)
:回傳 Applicative Traversable
Refactoring
import { pipe, Maybe, parseInt, traverse, I, maybe } from 'sanctuary'
let data = ['a', 'b', 'c']
pipe ([
traverse (Maybe) (parseInt (16)),
maybe ([]) (I)
]) (data) // ?
既然 traverse
可直接傳入 function,可將 parseInt (16)
直接傳入 traverse
即可。
Nothing
import { pipe, Maybe, parseInt, traverse, I, maybe } from 'sanctuary'
let data = ['a', 'b', 'x']
pipe ([
traverse (Maybe) (parseInt (16)),
maybe ([]) (I)
]) (data) // ?
若傳入 traverse
的 function 會造成其中任一 element 為 Nothing,則會停止後續運算直接回傳 Nothing。
parseInt (16) ('x')
會回傳 Nothing,因此最後結果為 Nothing,經過 maybe
處理後為 Empty Array。
Conclusion
- 若 function 回傳 Maybe,傳入
map
後會回傳 Array Maybe,此時我們很難從 Maybe 取出內部 Value,traverse
可將 Array Maybe 轉成 Maybe Array,如此就很容易從 Maybe 取出 Value。 traverse
允許我們傳入回傳 Applicative 的 function,因此 Maybe 也是 Applicative,因此也可直接傳入traverse
省略map
- 可發現當同樣傳入回傳 Maybe 的 function 時,
map
與traverse
所回傳的 type signature 剛好相反