iT邦幫忙

2021 iThome 鐵人賽

DAY 27
0
Software Development

Functional Programming For Everyone系列 第 27

Day 27 - State Monad II

在上一章,我們提到了如何用一般方法實作 PRNG 亂數生成器,本章將介紹 State Monad 以及改寫上一章的範例,廢話不多說讓我們看下去吧!

Introduction

concept

State a s

State Monad 的 constructor 也跟 Reader Monad一樣,都是放入函式,比較值得注意的是,State 裡面包含了 sa, s 表示為狀態, a 則是結果

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

State.of = a => State(s => [a, s])

Functor

而 State Functor 則可以將 a 進行 trasnform,

const State = run => ({
    run,
    map: f => State(a => {
        const [y, s] = run(a);
        return [f(y), s]
    })
})

這樣就可將前一篇的 randomInRange 先改為

const seed = 1;

const randomInRange = (min, max) => s => 
  State(generator).map(value).map(normalize(min, max)).run(s);

randomInRange(0, 1)(seed)

// [5, 1103527590] 

再來將前一章最後的範例改為

const nameList = ["jing", "jing*5", "jing-tech"];

const randomName = (from) => (seed) =>
  randomInRange(0, from.length)
    .map((index) => from[index])
    .run(seed);

const [name, r1] = randomName(nameList)(1); // ["jing*5", 1103527590]

是不是清楚很多了!!

Chain

const State = (run) => ({
  run,
  map: (f) =>
    State((a) => {
      const [y, s] = run(a);
      return [f(y), s];
    }),
  chain: f =>
      State(x => {
        const [y, s] = run(x);
        return f(y).run(s)
      }), 
});

當然也可以將兩個 State Monad 作結合,例如是要繼續精進自己,還是當懶蟲。

const randomInRange = (min, max) => 
  State(generator).map(value).map(normalize(min, max));
  
const randomFrom = (from) =>
  randomInRange(0, from.length).map((index) => from[index]);
  
const keepImprove = randomFrom(['Study', 'Coding', "Writing"]);
const lazy = randomFrom(['Couch Potato', 'Netflix']);
const seed = 1;
const result = randomInRange(0, 1)
  .map((n) => n === 1)
  .chain((bool) => (bool ? keepImprove : lazy))
  .run(seed); // ["Couch Potato", 377401600]

小結

OKAY,result 竟然是慫恿筆者當 Couch Potato,那就不客氣了!決定把剩下的留到下一章寫,感謝大家閱讀!!!

Reference

  1. State Monad

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

尚未有邦友留言

立即登入留言