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. Android之BInder分析

      MediaService的诞生: nt main(int argc, char** argv) { //FT,就这么简单?? //获得一个ProcessState实例 sp<ProcessS ...

  2. ttk.Treeview

    TTK的目的. TreeView控件的呈现层次结构,用户可以使用鼠标动作来显示或隐藏结构的任何部分. 与术语“树”的关联是由于编程实践:树结构是一个常见的程序设计.严格地说,在一个TreeView控件 ...

  3. MATLAB作图方法与技巧(一)

    下面从折线图.曲面图和图形说明与定制三个方面说明MATLAB作图的一些方法与技巧,注意,文中出现的单引号在MATLAB中实际运行的时候,需要改为MATLAB认可的单引号. 一. 作折线图 1.plot ...

  4. centos6.5 安装stardict 出现问题 [Errno 256] No more mirrors to try

    1. 下载startdict #wget http://downloads.naulinux.ru/pub/NauLinux/6x/i386/sites/School/RPMS/stardict-3. ...

  5. 集训考试题(CF510C Fox And Names的简化版)

    题目描述给定n个由小写字母组成的字符串,请你求出一个字母表顺序,使得这n个字符串是按照字典序升序排列的,数据保证存在合法的字母表顺序.如果存在多个解,输出字典序最小的那个. 输入格式第一行一个整数n. ...

  6. [BZOJ 1789] Necklace

    Link: BZOJ 1789 传送门 Solution: 感觉$n\le 50$可以随便乱搞啊…… 这里我是先找到3条链的失配位置,再找到这之后其中2条链最远的失配位置,统计即可 Code: #in ...

  7. 【权值分块】bzoj3685 普通van Emde Boas树

    权值分块,虽然渐进复杂度不忍直视,但其极小的常数使得实际运行起来比平衡树快,大多数情况和递归版权值线段树差不多,有时甚至更快.但是被zkw线段树完虐. #include<cstdio> # ...

  8. python3开发进阶-Django框架中form的查看校验方法is_valid()的源码,自定义验证方法

    form表单的校验方法is_valid() 点开我们发现这个函数里面只有两个方法方法,最终返回True or False 我们点进.is_bound属性,里面判断传输的数据不是空和上传文件不是空 点进 ...

  9. Java学习笔记(6)

    java是面向对象的语言. 对象:真实存在的唯一的事物. 类:实际就是对某种类型事物的共性属性与行为的抽取 面向对象的计算机语言的核心思想:找适合的对象做适合的事情. 如何找适合的对象呢: 1.sun ...

  10. kill -3 获取threaddump信息

    有些Java应用服务器是在控制台上运行,如Weblogic,为了方便获取threaddump信息,在weblogic启动的时候,会将其标准输出重 定向到一个文件,用"nohup ./star ...