在上一章,我們提到了如何用一般方法實作 PRNG 亂數生成器,本章將介紹 State Monad 以及改寫上一章的範例,廢話不多說讓我們看下去吧!
concept
State a s
State Monad 的 constructor 也跟 Reader Monad一樣,都是放入函式,比較值得注意的是,State 裡面包含了 s
與 a
, s
表示為狀態, a
則是結果
const State = run => ({
run,
})
State.of = a => State(s => [a, s])
而 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]
是不是清楚很多了!!
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,那就不客氣了!決定把剩下的留到下一章寫,感謝大家閱讀!!!