iT邦幫忙

2021 iThome 鐵人賽

DAY 25
0
Software Development

Functional Programming For Everyone系列 第 25

Day 25 - Reader Monad

今天來介紹 Reader Monad,其主要處理的就是 dependency injection,

痛點

說到 dependency injection 如果最壞的情況就是要將值不斷的傳下去,但中間的函式都不會用到該值

const toUpper = str => str.toUpperCase();
const exlaim  = str => str.concat('!');
const deps = {
    "i18n": {
        "HELLO FP!!": "嗨 函數式編程!"
    }
}

const f = (str, deps) => deps.i18n[str]
const g = (upper, deps) => f(exlaim(upper), deps)
const h = (str, deps) => g(toUpper(str), deps)

h('hello fp!', deps) // "嗨 函數式編程!"

可以看到 g 以及 h 就只是將 deps 傳下去而已,本身根本沒用到,這樣不是很冗餘嗎? 而 Reader Monad 就是來解決這個痛點的! 首先先來看看最初的起點 Function Modeling

Functions Modeling

什麼是 Functions Modeling 呢? 回想一下前面幾章無論是 Either, Maybe 又或是 IO 都是放入單一型別(Object, String, ...) ,但如果現在想要放入的是函式呢?

舉例來說


const Function = (run) => ({
    run,
})

如果想要讓 Function 變成是一個 Functor 呢?

const Function = run => ({
    run, 
    map: f => Function(x => f(run(x)))
})

可以看到 map 就是將函式進行 compose,

Function(toUpper)
    .map(exlaim)
    .run('hello fp!') // HELLO FP!!

那想要將兩個 Function Monad 進行 compose 呢?

const Function = run => ({
    run,
    map: f => Function(x => f(run(x))),
    chain: f => Function(x => f(run(x)).run(x))
})

接下來就可以將兩個 Monad 進行 compose 了!

Function(toUpper)
    .chain(upper => Function(x => exlaim(upper)))
    .run('hello fp!') // HELLO FP!!

也可將 Function 變成 pointed functor

Function.of = x => Fn(() => x)

大家這時應該就會好奇,那 x 是什麼呢? 可以先印出來看看

Function(toUpper)
    .chain(upper => Function(x => console.log(x, exlaim(upper))))
    .run('hello fp!') // hello fp! HELLO FP!!

沒錯 x 就是原本放入 run 的參數,而這有什麼用呢? 如果現在要做 dependency injection,例如 DB 的 config 注入等等,就可以派上很大的用場!

所以來改寫上述痛點!

Function.of('hello fp!')
  .map(toUpper)
  .chain((upper) => Function((deps) => deps.i18n[exlaim(upper)]))
  .run(deps); // 嗨 函數式編程!!

另外,Function ADT 通常會有一個優化的 API,ask,其主要就是取 run 傳入的值(deps)

Function.ask = Function(x => x)

再將上面程式碼套用 ask

Function.of('hello fp!')
  .map(toUpper)
  .map(exlaim)
  .chain((str) => Function.ask.map((deps) => deps.i18n[str]))
  .run(deps); // 嗨 函數式編程!!

而這也被稱為 Reader Monad!

小結

感謝大家閱讀!!

Reference

  1. Frontend Master

上一篇
Day 24 - Travserable
下一篇
Day 26 - State Monad I
系列文
Functional Programming For Everyone30

尚未有邦友留言

立即登入留言