The resultant in a State ADT instance can be used as a means of communication between different stateful transactions. It can be used to read and transform a portion of our state into a form that another transaction is dependent on. This allows us to only keep what is needed state, without filling it with calculations that are only needed for one or few transactions.

We take can take advantage of this by pulling not only a random number using the seed from our state, but also pulling a list of card and filtering them, to randomly select one from our calculated state. Then we use the resultant to store the calculation before we save the result to state.

Code for Random generator is here, which is not so important to this blog.

const {prop,assoc, State, identity, omit, curry, filter, converge,map, composeK, liftA2, equals, constant,option, chain, mapProps, find, propEq, isNumber, compose, safe} = require('crocks');
const {get, modify, of} = State; const state = {
cards: [
{id: 'green-square', color: 'green', selected: true, shape: 'square'},
{id: 'orange-square', color: 'orange', shape: 'square'},
{id: 'blue-triangle', color: 'blue', shape: 'triangle'}
],
hint: null,
seed: Date.now()
} // #region helper const liftState = fn => compose(
of,
fn
) // nextSeed :: Integer -> Integer
const nextSeed = seed =>
(seed * 1103515245 + 12345) & 0x7fffffff // value :: Integer -> Number
const value = seed =>
(seed >>> 16) / 0x7fff // normalize :: (Integer, Integer) -> Number -> Integer
const normalize = (min, max) =>
x => Math.floor(x * (max - min)) + min // getNextSeed :: () -> State AppState Integer
const getNextSeed = () =>
get(({ seed }) => nextSeed(seed)) // updateSeed :: Integer -> State AppState ()
const updateSeed = seed =>
modify(assoc('seed', seed)) // nextValue :: Integer -> State AppState Number
const nextValue = converge(
liftA2(constant),
liftState(value),
updateSeed
) // random :: () -> State AppState Number
const random =
composeK(nextValue, getNextSeed)
// #endregion // between :: (Integer, Integer) -> State AppState Integer
const between = (min, max) =>
random()
.map(normalize(min, max));

The only important piece is 'bewteen' function, which can generate the Number between a min & max range.

The  idea for what we are going to achieve is that:

  • Select all the unselected cards
  • Randomly choose one unselected card by using random function
  • Set the hint according to the selected card.

First, select all the unselected cards:

const selectState = (key, fn) => get(
compose(
map(fn),
prop(key)
)
)
const unselected = ({selected}) => !selected;
const getUnselectedCards = () => selectState('cards', filter(unselected)).map(option([]))

Second: Rnadomly choose one unselected card by using random function:

// randomIndex :: [a] -> State AppState a
const randomIndex = arr => between(0, arr.length)
const getAt = index => arr => arr[index];
const pickCard = converge(
liftA2(getAt),
randomIndex,
liftState(identity)
)

Last, Set the hint according to the selected card:

const over = (key, fn) => modify(
mapProps({[key]: fn})
)
const toHint = pick(['color', 'shape'])
// setHint :: Card -> State AppState()
const setHint = card => over('hint', constant(toHint(card)))
const nextHint = composeK(
setHint,
pickCard,
getUnselectedCards
)

-----------------

const {prop,assoc, pick, State, identity, omit, curry, filter, converge,map, composeK, liftA2, equals, constant,option, chain, mapProps, find, propEq, isNumber, compose, safe} = require('crocks');
const {get, modify, of} = State; const state = {
cards: [
{id: 'green-square', color: 'green', selected: true, shape: 'square'},
{id: 'orange-square', color: 'orange', shape: 'square'},
{id: 'blue-triangle', color: 'blue', shape: 'triangle'}
],
hint: null,
seed: Date.now()
} // #region helper const liftState = fn => compose(
of,
fn
) // nextSeed :: Integer -> Integer
const nextSeed = seed =>
(seed * 1103515245 + 12345) & 0x7fffffff // value :: Integer -> Number
const value = seed =>
(seed >>> 16) / 0x7fff // normalize :: (Integer, Integer) -> Number -> Integer
const normalize = (min, max) =>
x => Math.floor(x * (max - min)) + min // getNextSeed :: () -> State AppState Integer
const getNextSeed = () =>
get(({ seed }) => nextSeed(seed)) // updateSeed :: Integer -> State AppState ()
const updateSeed = seed =>
modify(assoc('seed', seed)) // nextValue :: Integer -> State AppState Number
const nextValue = converge(
liftA2(constant),
liftState(value),
updateSeed
) // random :: () -> State AppState Number
const random =
composeK(nextValue, getNextSeed)
// #endregion // between :: (Integer, Integer) -> State AppState Integer
const between = (min, max) =>
random()
.map(normalize(min, max)); // Get all unselected card
// Randomly choose an unselected Card
// Set hint const selectState = (key, fn) => get(
compose(
map(fn),
prop(key)
)
)
const unselected = ({selected}) => !selected;
const getUnselectedCards = () => selectState('cards', filter(unselected)).map(option([])) // randomIndex :: [a] -> State AppState a
const randomIndex = arr => between(0, arr.length)
const getAt = index => arr => arr[index];
const pickCard = converge(
liftA2(getAt),
randomIndex,
liftState(identity)
)
const over = (key, fn) => modify(
mapProps({[key]: fn})
)
const toHint = pick(['color', 'shape'])
// setHint :: Card -> State AppState()
const setHint = card => over('hint', constant(toHint(card)))
const nextHint = composeK(
setHint,
pickCard,
getUnselectedCards
) console.log(
nextHint()
.execWith(state)
)

[Javascript] Use a Pure RNG with the State ADT to Select an Element from State的更多相关文章

  1. [Functional Programming ADT] Adapt Redux Actions/Reducers for Use with the State ADT

    By using the State ADT to define how our application state transitions over time, we clear up the ne ...

  2. [Functional Programming ADT] Create State ADT Based Reducers (applyTo, Maybe)

    The typical Redux Reducer is function that takes in the previous state and an action and uses a swit ...

  3. [React + Functional Programming ADT] Connect State ADT Based Redux Actions to a React Application

    With our Redux implementation lousy with State ADT based reducers, it is time to hook it all up to a ...

  4. [Functional Programming ADT] Create a Redux Store for Use with a State ADT Based Reducer

    With a well defined demarcation point between Redux and our State ADT based model, hooking up to a R ...

  5. [Functional Programming ADT] Initialize Redux Application State Using The State ADT

    Not only will we need to give our initial state to a Redux store, we will also need to be able to re ...

  6. [Functional Programming ADT] Combine Multiple State ADT Based Redux Reducers

    Redux provides a convenient helper for combining many reducers called combineReducer, but it focuses ...

  7. [Functional Programming] Combine Multiple State ADT Instances with the Same Input (converge(liftA2(constant)))

    When combining multiple State ADT instances that depend on the same input, using chain can become qu ...

  8. [Functional Programming] Read and Transform Values from a State ADT’s State (get)

    Many times we need to access and transform state, either in part or in full, to be used when calcula ...

  9. [Functional Programming] Combine State Dependent Transactions with the State ADT (composeK to replace multi chian call)

    When developing a Finite State Machine, it is often necessary to apply multiple transitions in tande ...

随机推荐

  1. [ 手记 ] 联想rd650服务器整列及系统安装

    联想 RD650服务器 磁盘阵列:http://wenku.baidu.com/view/b364c2db5f0e7cd185253644.html?from=search 该服务器安装系统需要BIO ...

  2. Hibernate 和 Mybatis的区别

    第一方面:开发速度的对比 就开发速度而言,Hibernate的真正掌握要比Mybatis来得难些.Mybatis框架相对简单很容易上手,但也相对简陋些.个人觉得要用好Mybatis还是首先要先理解好H ...

  3. CSS入门之定义和应用格式

    1:定义 1:定义单个属性 property:value 例如: color:white(属性和值之间用冒号隔开) 2:定义多个属性 property:value;property:value 例如: ...

  4. 计蒜客 30999.Sum-筛无平方因数的数 (ACM-ICPC 2018 南京赛区网络预赛 J)

    J. Sum 26.87% 1000ms 512000K   A square-free integer is an integer which is indivisible by any squar ...

  5. Maven学习笔记2

    Maven安装配置 1.下载Maven 官方地址:http://maven.apache.org/download.cgi 将下载的压缩包解压到你要安装 Maven 的文件夹.假设你解压缩到文件夹 – ...

  6. 差分数组 and 树上差分

    差分数组 定义 百度百科中的差分定义 //其实这完全和要讲的没关系 qwq 进去看了之后是不是觉得看不懂? 那我简单概括一下qwq 差分数组de定义:记录当前位置的数与上一位置的数的差值. 栗子 容易 ...

  7. Codeforces Round #352 (Div. 1) B. Robin Hood (二分)

    B. Robin Hood time limit per test 1 second memory limit per test 256 megabytes input standard input ...

  8. Nginx+tomcat集群redis共享session应用方案

    部署环境 主机 软件版本 192.168.88.1 nginx-1.12.2+redis-3.2.11 192.168.88.2 apache-tomcat-7.0.79 + jdk1.8 192.1 ...

  9. Express下使用formidable实现POST表单上传文件并保存

    Express下使用formidable实现POST表单上传文件并保存 在上一篇文章中使用formidable实现了上传文件,但没将它保存下来. 一开始,我也以为是只得到了文件的相关信息,需要用fs. ...

  10. [BZOJ 2395] Time is money

    Link: BZOJ 2395 传送门 Solution: 算是一类比较经典的模型: 即对于一类经典问题,每点由1个权值化为2个权值,最终求$sigma(val_1)*sigma(val_2)$ 对于 ...