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. 使用python抓取并分析数据—链家网(requests+BeautifulSoup)(转)

    本篇文章是使用python抓取数据的第一篇,使用requests+BeautifulSoup的方法对页面进行抓取和数据提取.通过使用requests库对链家网二手房列表页进行抓取,通过Beautifu ...

  2. nginx [error] open() "/usr/local/nginx/logs/nginx.pid" failed的解决

    今天关闭nginx后重启不了: nginx -s reload 结果报错: nginx: [error] open() "/usr/local/nginx/logs/nginx.pid&qu ...

  3. beijing2016

    4625: [BeiJing2016]水晶 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 201  Solved: 70[Submit][Status ...

  4. box-shadow用法简介

    语法: <strong>box-shadow:</strong><em><length></em><em><length& ...

  5. 使用Xshell上传下载文件

    很多时候我们需要在Windows跟Linux之间,或者Linux跟Linux之间传文件,这里我们讲的是使用Xshell实现文件上传下载. 一.使用rz,sz实现Windows,linux上传下载 1. ...

  6. scrapy中Selector的使用

    scrapy的Selector选择器其实也可以用来解析,今天主要总结下css和xpath的用法,其实我个人最喜欢用css 以慕课网嵩天老师教程中的一个网页为例,python123.io/ws/demo ...

  7. Codeforces 1039A. Timetable

    题目地址:http://codeforces.com/problemset/problem/1039/A 题目的关键在于理清楚思路,然后代码就比较容易写了 对于每一个位置的bus,即对于每一个i(i& ...

  8. [BZOJ 3233] 找硬币

    Link: BZOJ 3233 传送门 Solution: 在本蒟蒻看来算是一道比较神的$dp$了 一开始转移方程都没看出来…… 首先,如果确定了最大面值,是能推出其他面值的所有可能值的 从而发现最大 ...

  9. 【kd-tree】bzoj3489 A simple rmq problem

    Orz zyf教给蒟蒻做法 蒟蒻并不会这题正解……(可持久化树套树?...Orz 对于每个点,我们可以求出pre[i],nex[i],那么询问的答案就是:求max (a[i]),其中 i 满足(pre ...

  10. 【分块】【树状数组】bzoj3744 Gty的妹子序列

    离散化,分块. 预处理出:ans[i][j] 第i块到第j块的逆序对数. f[i][j] 第1~i块中大于j的数的个数. g[i][j] 第1~j块中小于j的数的个数. 每次询问时对于整块部分可以O( ...