[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 mreducecatamorphism 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 ...
随机推荐
- Anaconda 2和3在Win10上共存
1. 安装Anaconda 2和3 Anaconda 2中的python2为主,Anaconda 3中的python3为辅.先装Anaconda 2,并在安装时选择注册为系统python,再装Anac ...
- Java坦克大战 (三) 之可完全控制坦克朝八个方向运动
本文来自:小易博客专栏.转载请注明出处:http://blog.csdn.net/oldinaction 在此小易将坦克大战这个项目分为几个版本,以此对J2SE的知识进行回顾和总结,希望这样也能给刚学 ...
- [ 总结 ] RHEL6/Centos6 使用OpenLDAP集中管理用户帐号
使用轻量级目录访问协议(LDAP)构建集中的身份验证系统可以减少管理成本,增强安全性,避免数据复制的问题,并提供数据的一致性.
- 官方文档,才是正途-docker-compose
需要的ingress网络映射,还是host宿主机端口映射: https://docs.docker.com/compose/compose-file/#secrets ================ ...
- PHP常用到的功能函数
1.PHP加密解密 PHP加密和解密函数可以用来加密一些有用的字符串存放在数据库里,并且通过可逆解密字符串,该函数使用了base64和MD5加密和解密. 复制代码代码如下: function encr ...
- 在小程序开发中使用 npm
微信小程序在发布之初没有对 npm 的支持功能,这也是目前很多前端开发人员在熟悉了 npm 生态环境后,对微信小程序诟病的地方. 微信小程序在 2.2.1 版本后增加了对 npm 包加载的支持,使得小 ...
- [CTSC2017]最长上升自序列(伪题解)(Dilworth's theorem+网络流)
部分分做法很多,但每想出来一个也就多5-10分.正解还不会,下面是各种部分分做法: Subtask 1:k=1 LCS长度最长为1,也就是说不存在j>i和a[j]>a[i]同时成立.显然就 ...
- [CTSC2017]游戏(Bayes定理,线段树)
传送门:http://uoj.ac/problem/299 题目良心给了Bayes定理,但对于我这种数学渣来说并没有什么用. 先大概讲下相关数学内容: 1.定义:$P(X)$ 表示事件$X$发生的概率 ...
- 【线段树】Codeforces Round #393 (Div. 1) C. Nikita and stack
就是给你一些元素的进栈 出栈操作,不按给定的顺序,要求你对于每次输入,都依据其及其之前的输入,判断出栈顶的元素是谁. 用线段树维护,每次push,将其位置的值+1,pop,将其位置的值-1.相当于寻找 ...
- 【分块】【树状数组】bzoj3787 Gty的文艺妹子序列
题解懒得自己写了,Orz一发wangxz神犇的: http://bakser.gitcafe.com/2014/12/04/bzoj3787-Gty%E7%9A%84%E6%96%87%E8%89%B ...