Using Naive JS:
const {modify, get} = require('crocks/State'); const K = require('crocks/combinators/constant'); const B = require('crocks/combinators/composeB'); const assign = require('crocks/helpers/assign'); const prop = require('crocks/Maybe/prop'); const option = require('crocks/pointfree/option'); // rando : Integer -> State Object Float const rando = x => { const seed = (1103515245 * x + 12345) & 0x7fffffff const value = (seed >>> 16) / 0x7fff; return modify(assign({seed})) // update the seed Pair(_, seed) .map(K(value)); // update the value Pair(value, seed) } // pullRandom :: Integer -> State Object Float const pullRandom = defSeed => get(s => pluckSeed(defSeed)).chain(rando); // pluckSeed :: Integer -> Object -> Integer const pluckSeed = def => B(option(def), prop('seed')) module.exports = { pullRandom };
The main problem is inside 'rando' function, not really a FP way doing stuff.
Arrow approach:
const {modify, get} = require('crocks/State'); const Arrow = require('crocks/Arrow'); const K = require('crocks/combinators/constant'); const B = require('crocks/combinators/composeB'); const assign = require('crocks/helpers/assign'); const branch = require('crocks/Pair/branch'); const prop = require('crocks/Maybe/prop'); const option = require('crocks/pointfree/option'); const merge = require('crocks/pointfree/merge'); // calcSeed :: Arrow Integer const calcSeed = Arrow(x => (1103515245 * x + 12345) & 0x7fffffff); // value :: Arrow (Pair Integer) -> Pair (Integer Float) const value = Arrow(x => (x >>> 16) / 0x7fff).second(); // genRandom :: Arrow Integer Object const genRandom = calcSeed .map(branch) .compose(value) .map(p => [p.fst(), p.snd()]) // rando : Integer -> State Object Float const rando = x => { const [seed, value] = genRandom.runWith(x); return modify(assign({seed})) // update the seed Pair(_, seed) .map(K(value)); // update the value Pair(value, seed) } // pullRandom :: Integer -> State Object Float const pullRandom = defSeed => get(s => pluckSeed(defSeed)).chain(rando); // pluckSeed :: Integer -> Object -> Integer const pluckSeed = def => B(option(def), prop('seed')) module.exports = { pullRandom };
It becomes complex with we need to do Pari and Arrow.
State version:
const {modify, get} = require('crocks/State'); const B = require('crocks/combinators/composeB'); const assign = require('crocks/helpers/assign'); const prop = require('crocks/Maybe/prop'); const option = require('crocks/pointfree/option'); //initialState :: GameState const initialState = { deck: [], seed: 23 } // newSeed :: Int -> INt const newSeed = seed => (1103515244 * seed + 12345) & 0x7fffffff; // calcValue :: Int -> Float const calcValue = seed => (seed >>> 16) / 0x7fff; // pluckSeed :: Integer -> GameState -> Integer const pluckSeed = def => B(option(def), prop('seed')); // getSeed :: () -> State GameState Int const getSeed = () => get(pluckSeed({seed: 0})); // putSeed :: Int -> State GameState () const putSeed = seed => modify(assign({seed})); // genSeed :: () -> State GameState () // get default seed // map to a new seed // update current seed in state const genSeed = () => getSeed() .map(newSeed) .chain(putSeed); // evaluate :: () -> State GameState Float const evaluate = () => getSeed() .map(calcValue); // pullRandom :: () -> State GameState Float const pullRandom = () => genSeed() .chain(evaluate); console.log( pullRandom() .runWith(initialState) )
The idea is easier to follow and thinking in a way of state transition.