嗨大家好,真希望一天能有 48 小時,不然這主題都要分到四部曲了,沒錯,應該會有四部曲! 抱歉了!
上次提到了 map
與 chain
的用法,當然也可以用將多個 State monad 套用在函式參數長度為多個以上
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);
}),
ap: (m) =>
State((x) => {
const [y, s] = run(x);
return m.map(y).run(s);
}),
});
而這概念也提過很多次,就不多做贅述了~
State.of(1).map(R.add).ap(State.of(1)).run() // [3, undefined]
如果今天是要將一個 Array 內多個 State Monad (Array<State>
)進行運算並轉換成 State Array s
呢? 當然也可以還記得在 Traversable 那章提過的嗎? 其要件就是同時要有 Foldable 以及 Functor 的特性
首先來記得 Array
也有 traverse 的特性嗎?
Array.prototype.traverse = function (T, f) {
return this.reduce(
(acc, val) =>
f(val)
.map((x) => (y) => y.concat(x))
.ap(acc),
T.of([])
);
};
在來就是準備多個 State Monad 塞到陣列
const generator = (seed) => {
const nextSeed = (seed * 1103515245 + 12345) & 0x7fffffff;
return [nextSeed, nextSeed];
};
const value = (seed) => (seed >>> 16) / 0x7fff;
const normalize = (min, max) => (x) => Math.floor(x * (max - min)) + min;
const randomInRange = (min, max) =>
State(generator).map(value).map(normalize(min, max));
const randomFrom = (from) =>
randomInRange(0, from.length).map((index) => from[index]);
const FisrtRandom = randomFrom(['FP', 'OOP', 'BOTH']);
const MiddleRandom = randomFrom(['IS', 'ARE']);
const LastRandom = randomFrom(['GOOD', 'SUCK']);
const combineIt = [FisrtRandom, MiddleRandom, LastRandom]
這樣就完成多組同時進行隨機抽取了!!! 猜猜這次的結果會是什麼吧!
const seed = 1;
combineIt.traverse(State, R.identity)
.map(([x, y, z]) => `${x} ${y} ${z}`)
.run(seed);
// ["FP IS SUCK", 333417792]
Oops! 怎麼會這樣... 突然覺得變搞笑文章系列,Anyway, That's it for today!
感謝大家閱讀!!!