[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 Functor
. It becomes even more powerful when both of those are Chain
s, allowing us to apply each Functor
’s special properties and effects for a given computation.
We witness this power first hand by combining our beloved State
with a Pair
type mixing the ability to randomly pick an index from an Array
using State
and use it to draw an element from the Array
. We will build up to an easy to use interface that allows us to pull as many elements as we need, by chaining on single State transaction.
// 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 {prop,assoc, 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' ],
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)); // draw :: Integer -> Deck -> Deck
const draw = compose(
chain,
drawCardAt
);
// const draw = index => deck => deck.chain(drawCardAt(index)) // drawRandom :: Deck -> State AppState Deck
const drawRandom = converge(
liftA2(draw),
compose(
randomIndex,
snd
),
liftState(identity)
) console.log(
getDeck()
.chain(drawRandom)
.chain(drawRandom)
.chain(drawRandom)
.chain(drawRandom)
.evalWith(state).fst()
)
[Functional Programming] Randomly Pull an Item from an Array with the State ADT (Pair)的更多相关文章
- Beginning Scala study note(4) Functional Programming in Scala
1. Functional programming treats computation as the evaluation of mathematical and avoids state and ...
- a primary example for Functional programming in javascript
background In pursuit of a real-world application, let’s say we need an e-commerce web applicationfo ...
- Functional programming
In computer science, functional programming is a programming paradigm, a style of building the struc ...
- 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 ...
- Java 中的函数式编程(Functional Programming):Lambda 初识
Java 8 发布带来的一个主要特性就是对函数式编程的支持. 而 Lambda 表达式就是一个新的并且很重要的一个概念. 它提供了一个简单并且很简洁的编码方式. 首先从几个简单的 Lambda 表达式 ...
- Functional programming idiom
A functional programming function is like a mathematical function, which produces an output that typ ...
- 关于函数式编程(Functional Programming)
初学函数式编程,相信很多程序员兄弟们对于这个名字熟悉又陌生.函数,对于程序员来说并不陌生,编程对于程序员来说也并不陌生,但是函数式编程语言(Functional Programming languag ...
- Functional Programming 资料收集
书籍: Functional Programming for Java Developers SICP(Structure and Interpretation of Computer Program ...
随机推荐
- 【bzoj3289】mato的文件管理
首先允许离线,一眼莫队…… 然后考虑对于每次移动,这不就是让你求逆序对嘛(QAQ) 考虑怎么移动? 每次在最后添加一个数,比这个数大的数都会与其形成一个逆序对 每次在最后移除一个数,比这个数大的数都会 ...
- delphi.memory.分配及释放---New/Dispose, GetMem/FreeMem及其它函数的区别与相同,内存分配函数
来自:http://www.cnblogs.com/qiusl/p/4028437.html?utm_source=tuicool&utm_medium=referral ---------- ...
- Eclipse默认标签TODO,XXX,FIXME和自定义标签
1 TODO 表示需要实现,但目前还未实现的功能 2 XXX 勉强可以工作,但是需要改进的功能 3 FIXME 代码是错误的,不能工作,需要修复 4.自定义标签 window-->prefere ...
- css行高line-height的用法
一.line-height语法 line-height属性的具体定义列表如下: 语法: line-height : normal | <实数> | <长度> | <百分比 ...
- laravel获取checkbox值的小技巧
以前老是用三元运算符来判断,现在有了更好的方法: 1.html代码 <input type="hidden" name="approved" value= ...
- Oracle迁移到DB2常用转换
因为项目需要,要将Oracle上的东西转移到DB2,于是收集整理了一些需要修改点的注意事项,拿出来大家分享. ORACLE和DB2实现相同功能的实例(主要以Oracle8I和DB2 7.X为例,已测试 ...
- [thinkphp]验证码不显示: 图像因存在错误无法显示
我只想说,该死的BOM FUKKKKK!!!!!!!!
- Oralce聚合多行
拼接的字符串长度满足varchar2(4000)时, 可以用 LISTAGG(NAME, '_') WITHIN GROUP(ORDER BY LEVEL_T DESC) 当拼接大段文本时,采用 10 ...
- 使用es索引遇到的问题记录
1设置es索引的运行内存: 直接在启动文件里面改就好,启动命令是elasticsearch.bat,用notepad++编辑这个文件,里面添加这样的一行:SET ES_HEAP_SIZE=10g即可 ...
- Bellman - Ford 算法解决最短路径问题
Bellman - Ford 算法: 一:基本算法 对于单源最短路径问题,上一篇文章中介绍了 Dijkstra 算法,但是由于 Dijkstra 算法局限于解决非负权的最短路径问题,对于带负权的图就力 ...