[Functional Programming] Pull Many Random Numbers in a Single State ADT Transaction
We have the ability to select a single random card from a pile of twelve cards, but we would like to pull a total of nine. Not only that, we would like to match the same transition functions we have been writing all along.
Lucky for use there are three types of functions, or morphisms that we can use to get us everything we need. We use an anamorphism to expand our one function into a list of nine functions. Each of these functions are endomorphisms, so we can use the mreduce
catamorphism with the Endo
Monoid to fold them down into one function that we can use to get this action into our state transactions.
const { mreduce, prop,assoc, Endo, Pair, pick, bimap, State, snd, identity, omit, curry, filter, fanout, converge,map, composeK, liftA2, equals, constant,option, chain, mapProps, find, propEq, isNumber, compose, safe} = require('crocks');
const {get, modify, of} = State; const state = {
colors: [ 'orange', 'green', 'blue', 'yellow' ],
shapes: [ 'square', 'triangle', 'circle' ],
cards: null,
seed: Date.now()
}; const liftState = (fn) => compose(
of, fn
);
const getState = key => get(prop(key)) // #region random
// nextSeed :: Integer -> Integer
const nextSeed = seed =>
(seed * + ) & 0x7fffffff // value :: Integer -> Number
const value = seed =>
(seed >>> ) / 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) // between :: (Integer, Integer) -> State AppState Integer
const between = (min, max) =>
random()
.map(normalize(min, max)); const randomIndex = xs => between(, xs.length);
// #endregion // #region generate const getColors = () => getState('colors').map(option([]));
const getShapes = () => getState('shapes').map(option([]));
const buildCard = curry((color, shape) => ({
id: `${color}-${shape}`,
color,
shape
}));
const buildCards = liftA2(buildCard);
const generateCards = converge(
liftA2(buildCards),
getColors,
getShapes
); // #endregion // #region draw
const getAt = index => array => Array.of(array[index]);
const unsetAt = index => array => [
...array.slice(, index),
...array.slice(index + )
];
const drawCardAt = index => fanout(getAt(index), unsetAt(index));
// #endregion // getDeck :: () -> State AppState Deck
const getDeck = () => generateCards()
.map(xs => Pair([], xs));
/**
Pair(
[ ],
[ { id: "orange-square", color: "orange", shape: "square" }, { id: "orange-triangle", color: "orange", shape: "triangle" }, { id: "orange-circle", color: "orange", shape:
"circle" }, { id: "green-square", color: "green", shape: "square" }, { id: "green-triangle", color: "green", shape: "triangle" }, { id: "green-circle", color: "green", shape: "circle" }, { id: "blue-square", color: "blue", shape: "square" }, { id: "blue-triangle", color: "blue", shape: "triangle" }, { id: "blue-circle", color: "blue", shape: "circle" }, { id: "yellow-square", color: "yellow", shape: "square" }, { id: "yellow-triangle", color: "yellow", shape: "triangle" }, { id: "yellow-circle", color: "yellow", shape: "circle" } ]
)
*/
// draw :: Integer -> Deck -> Deck
const draw = compose(
chain,
drawCardAt
);
// const draw = index => deck => deck.chain(drawCardAt(index)) // drawRandom :: Deck -> State AppState Deck
// From the right side pair, get a random index, then draw the card by index
const drawRandom = converge(
liftA2(draw),
compose(
randomIndex,
snd
),
liftState(identity)
) console.log(
getDeck()
.chain(drawRandom)
.chain(drawRandom)
.chain(drawRandom)
.evalWith(state).fst()
)
/**
* [ { id: 'orange-square', color: 'orange', shape: 'square' },
{ id: 'blue-triangle', color: 'blue', shape: 'triangle' },
{ id: 'blue-square', color: 'blue', shape: 'square' } ]
*/
console.log(
getDeck()
.chain(drawRandom)
.chain(drawRandom)
.chain(drawRandom)
.evalWith(state).snd()
)
/**
[ { id: 'orange-triangle', color: 'orange', shape: 'triangle' },
{ id: 'orange-circle', color: 'orange', shape: 'circle' },
{ id: 'green-square', color: 'green', shape: 'square' },
{ id: 'green-triangle', color: 'green', shape: 'triangle' },
{ id: 'green-circle', color: 'green', shape: 'circle' },
{ id: 'blue-circle', color: 'blue', shape: 'circle' },
{ id: 'yellow-square', color: 'yellow', shape: 'square' },
{ id: 'yellow-triangle', color: 'yellow', shape: 'triangle' },
{ id: 'yellow-circle', color: 'yellow', shape: 'circle' } ]
*/ const repeat = (num, elem) =>
num ===
? [elem]
: repeat(num - , elem).concat([elem]); const drawNine = mreduce(
Endo,
repeat(, chain(drawRandom))
); const drawFromDeck = compose(
drawNine, getDeck
)
const over = (key, fn) => modify(mapProps({[key]: fn}));
const setCards = deck => over('cards', constant(deck.fst())) const pickCards = composeK(setCards, drawFromDeck) console.log(
pickCards()
.execWith(state)
)
[Functional Programming] Pull Many Random Numbers in a Single State ADT Transaction的更多相关文章
- 2017 ACM-ICPC, Universidad Nacional de Colombia Programming Contest K - Random Numbers (dfs序 线段树+数论)
Tamref love random numbers, but he hates recurrent relations, Tamref thinks that mainstream random g ...
- [Functional Programming] Using JS, FP approach with Arrow or State Monad
Using Naive JS: const {modify, get} = require('crocks/State'); const K = require('crocks/combinators ...
- [Functional Programming Monad] Refactor Stateful Code To Use A State Monad
When we start to accumulate functions that all work on a given datatype, we end up creating a bunch ...
- [Functional Programming] Randomly Pull an Item from an Array with the State ADT (Pair)
Functor composition is a powerful concept that arises when we have one Functor nested in another Fun ...
- Functional programming
In computer science, functional programming is a programming paradigm, a style of building the struc ...
- Generating Gaussian Random Numbers(转)
Generating Gaussian Random Numbers http://www.taygeta.com/random/gaussian.html This note is about th ...
- Beginning Scala study note(4) Functional Programming in Scala
1. Functional programming treats computation as the evaluation of mathematical and avoids state and ...
- Functional Programming without Lambda - Part 2 Lifting, Functor, Monad
Lifting Now, let's review map from another perspective. map :: (T -> R) -> [T] -> [R] accep ...
- Functional Programming without Lambda - Part 1 Functional Composition
Functions in Java Prior to the introduction of Lambda Expressions feature in version 8, Java had lon ...
随机推荐
- [TJOI2007]segment
题目描述 在一个 n*n 的平面上,在每一行中有一条线段,第 i 行的线段的左端点是(i, L(i)),右端点是(i, R(i)),其中 1 ≤ L(i) ≤ R(i) ≤ n. 你从(1, 1)点出 ...
- HBuilder开发移动App——manifest.json文件解析
以前做过Android App开发,对于各项配置都是在AndroidManifest.xml文件中完成的,包括权限的设定.图标.标签.App的名字.Activity注册等等 使用HBuilder开发移 ...
- Centos 下,配置 Apache + Python + Django + postgresSQL 开发环境
用 Python 搭建一个 Web 服务器 文章结构 一.安装 Apache.Python.django 二.安装 mod_wsgi,Apache 为 Python 提供的 wsgi 模块 三.将 ...
- poj 3254(状态压缩+动态规划)
http://poj.org/problem?id=3254 题意:有一个n*m的农场(01矩阵),其中1表示种了草可以放牛,0表示没种草不能放牛,并且如果某个地方放了牛,它的上下左右四个方向都不能放 ...
- java Socket启动服务
java -cp /Library/WebServer/Documents/Java/test/src com.zhidian.soft.sendOfClick localhost 8888 java ...
- HDU 6315.Naive Operations-线段树(两棵树合并)(区间单点更新、区间最值、区间求和)+思维 (2018 Multi-University Training Contest 2 1007)
6315.Naive Operations 题意很好理解,但是因为区间求和求的是向下取整的a[i]/b[i],所以直接分数更新区间是不对的,所以反过来直接当a[i]==b[i]的时候,线段树对应的位置 ...
- HDU 1754.I Hate It-结构体版线段树(单点更新+区间查询最值)
I Hate It Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total S ...
- dfs序七个经典问题[转]
dfs序七个经典问题 参考自:<数据结构漫谈>-许昊然 dfs序是树在dfs先序遍历时的序列,将树形结构转化成序列问题处理. dfs有一个很好的性质:一棵子树所在的位置处于一个连续区间中. ...
- ACM-ICPC北京赛区(2017)网络赛2【后缀数组+Java//不会】
#1579 : Reverse Suffix Array 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 There is a strong data structure ...
- 灯泡游戏 (Kruskal)(并查集)
灯泡游戏 时间限制: 1 Sec 内存限制: 64 MB提交: 9 解决: 4[提交][状态][讨论版] 题目描述 有 一个n行m列的矩阵,左上角坐标是(0,0),右下角坐标是(n-1,m-1). ...