點燈坊

失くすものさえない今が強くなるチャンスよ

使用 traverse 將 Array Maybe 轉成 Maybe Array

Sam Xiao's Avatar 2021-07-23

當引入 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。

traverse000

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 Maybe
  • traverse (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 為 Traversable
  • f (t b):回傳 Applicative Traversable

traverse001

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 即可。

traverse002

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。

traverse003

Conclusion

  • 若 function 回傳 Maybe,傳入 map 後會回傳 Array Maybe,此時我們很難從 Maybe 取出內部 Value,traverse 可將 Array Maybe 轉成 Maybe Array,如此就很容易從 Maybe 取出 Value。
  • traverse 允許我們傳入回傳 Applicative 的 function,因此 Maybe 也是 Applicative,因此也可直接傳入 traverse 省略 map
  • 可發現當同樣傳入回傳 Maybe 的 function 時,maptraverse 所回傳的 type signature 剛好相反

Reference

Sanctuary, traverse