[Functional Programming] Using naive JS, FP approach with Arrow or State Monad

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. 

猜你喜欢

转载自www.cnblogs.com/Answer1215/p/10601436.html