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. 2.aiomysql实现对数据库异步读取

    有一个库叫做aiomysql,这是一个基于asyncio和pymysql的库.至于为什么可以在tornado中使用,是因为高版本tornado的底层使用了asyncio. import asyncio ...

  2. DRF的过滤与排序

    过滤 对于列表数据可能需要根据字段进行过滤,我们可以通过添加 django-filter 扩展来增强支持. pip install django-filter 在配置文件中增加过滤后端的设置: INS ...

  3. CentOS7配置阿里云yum源和EPEL源

    配置阿里云yum源(参考:http://mirrors.aliyun.com/help/centos) 1.备份 [root@bogon ~]# cd /etc/yum.repos.d/ [root@ ...

  4. AC日记——病毒侵袭 hdu 2896

    2896 思路: 好题: 代码: #include <queue> #include <cstdio> #include <cstring> using names ...

  5. HTTP 协议基本知识

    HTTP协议    7.1.什么是HTTP协议:        HTTP协议是用来规定浏览器客户端和服务器通信的方式 7.2.基本原则        基于请求响应模型        一次请求对应一次响 ...

  6. F - Oil Deposits 【地图型BFS+联通性】

    The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSu ...

  7. Validate on POST data

    1. Basic validate  on bean's attribute. @Notnull @Max @Min @Pattern ... 2. Validate by logic 1) pass ...

  8. 模板—数据结构—LCT

    模板—数据结构—LCT Code: #include <cstdio> #include <algorithm> using namespace std; #define N ...

  9. 贮油点问题(C++)

    贮油点问题…..一道送命系列的递推… 描述 Description 一辆重型卡车欲穿过S公里的沙漠,卡车耗汽油为1升/公里,卡车总载油能力为W公升.显然卡车装一次油是过不了沙漠的.因此司机必须设法在沿 ...

  10. uestc1633

    uestc1633 题意 给你一个大小为 \(n\) 的集合 \(S\) ,集合里有 \(n\) 个互不相同正整数,有 \(q\) 个询问,每次询问是否能选择 \(S\) 中的一些数字 ( 同一个数字 ...