點燈坊

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

如何使 Array Array Maybe 轉成 Array Maybe Array 方便 justs 運算 ?

Sam Xiao's Avatar 2021-07-25

當引入 Maybe 後,若 Function 會回傳 Maybe,則適當使用 traversejusts 將使 Function Pipeline 更為順暢。

Version

Sanctuary 3.1.0

traverse

import { pipe, compose, Maybe, ifElse, Just, Nothing, K, equals, gte, mult, map, traverse, join, justs, maybe, mean, I } from 'sanctuary'

let data = [[2, 4, 5], [6, 0, 7], [1, 3, 8]]

let score = ifElse
  (equals (0))
  (K (Nothing))
  (ifElse
    (gte (5)) 
    (compose (Just) (mult (2))) 
    (Just))

pipe ([
  map (traverse (Maybe) (score)),
  justs, 
  join,
  mean,
  maybe (0) (I)
]) (data) // ?

第 3 行

let data = [[2, 4, 5], [6, 0, 7], [1, 3, 8]]

每個 Array 代表一個人 3 局的得分數,共有 3 人參賽,其計分規則如下:

  • 若有人其中一局為 0 分,則該人分數都不列入計算
  • 若該局分數大於 5 分,則分數乘以 2

最後求出每局平均分數。

第 5 行

let score = ifElse
  (equals (0))
  (K (Nothing))
  (ifElse
    (gte (5)) 
    (compose (Just) (mult (2))) 
    (Just))

使用 ifElse 組合 score

由於若有人其中一局為 0 分則不列入計算,因此 score 決定回傳 Nothing:

  • K (Nothing):若分數為 0 則回傳 Nothing
  • compose (Just) (mult (2)) :若分數大於 5 則成以 2 回傳 Just
  • Just:若分數小於 5 則只回傳 Just

13 行

pipe ([
  map (traverse (Maybe) (score)),
  justs, 
  join,
  mean,
  maybe (0) (I)
]) (data) // ?

使用 pipe 組合 f

  • map (traverse (Maybe) (score))

    • 由於傳入為 Array Array,map 是應付最外層 map
    • 對於內層 Array,原本應該使用 map (score),但因為 score 回傳 Maybe,因此內層為 Array Maybe
    • 考慮將配合外層 Array 將 Nothing 忽略,因此改用 traverse (Maybe) 將內層轉為 Maybe Array
    • 最後結果為 Array Maybe Array
  • justs:從 Array Maybe 忽略 Nothing,並解開 Just,回傳 Array Array

  • join:將 Array Array 攤平成一層 Array

  • mean:從 Array 計算出平均值,但 mean 回傳 Maybe

  • maybe (0) (I):解開 Maybe

traverse000

Conclusion

  • 因為需求是 0 分不列入計算,因此適合使用 justs 忽略 Nothing
  • justs 會將 Array Maybe 中的 Nothing 忽略,因此特別使用 traverse 將內層 Array Maybe 轉成 Maybe Array,才可配合外層形成 Array Maybe