[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 ...
随机推荐
- 【 Linux 】lvs-dr模型实现HA,后端Nginx、PHP、MySQL分离 搭建wordpress站点
要求: 1. wordpress程序通过nfs共享给各个realserver 2. 后端realserver中的nginx和php分离 网络结构图: 环境说明: OS:centos6 ...
- js面向对象编程(三)非构造函数的继承(转载)
Javascript面向对象编程(三):非构造函数的继承 今天是最后一个部分,介绍不使用构造函数实现"继承". 一.什么是"非构造函数"的继承? 比如,现在有一 ...
- ETL(Extract-Transform-Load的缩写,即数据抽取、转换、装载的过程)
ETL(Extract-Transform-Load的缩写,即数据抽取.转换.装载的过程)
- Spring boot集成redis初体验
pom.xml: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="ht ...
- [thinkPHP] buildSql可以查看tp CURD操作对应的SQL
$goods = M('Goods')->where($map)->buildSql(); echo $goods;
- P1059 明明的随机数【去重排序】
题目描述 明明想在学校中请一些同学一起做一项问卷调查,为了实验的客观性,他先用计算机生成了N个1到1000之间的随机整数(N≤100),对于其中重复的数字,只保留一个,把其余相同的数去掉,不同的数对应 ...
- 树上两点的最近公共祖先问题(Least Common Ancestors)
概念: 对于有根树T的两个节点u,v,最近公共祖先LCA(T, u, v)表示一个节点 x, 满足 x 是 u , v 的祖先且 x 的深度尽可能的大.即从 u 到 v 的路径一定经过点 x. 算法: ...
- MySQL 将某个字段值的记录排在最后,其余记录单独排序
1.按 status 值 2 5 3 的顺序排序,值相同则按修改时间排序 order by FIELD(status,2,5,3),a.ModifyTime desc 2.将 status = 3 的 ...
- oracle tablespace usage status
select a.tablespace_name, a.bytes / 1024 / 1024 "Sum MB", (a.bytes - b.bytes) / 1024 / 102 ...
- [LOJ6436]神仙的游戏
感觉border的性质还是挺神奇的 一个border的性质是$S$有长度为$len$的border当且仅当对$\forall i\equiv j\left(\bmod(n-len)\right)$有$ ...