[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 ...
随机推荐
- 新版谷歌浏览器设置flash插件不提示步骤
1.先去chrome实验室界面chrome://flags/#enable-ephemeral-flash-permission选择取消Disabled.取消该实验室选项. 2.然后去chrome:/ ...
- xpath用法(持续更新ing)
article:选取所有article元素的所有子节点 /article:选取根元素article article/a:选取所有属于article的子元素的a元素 //div:选取所有div元素 ar ...
- heightCharts改变图表内图标的样式:链接外部图片
series: [{ name: '东京', marker: { symbol: 'url(https://www.highcharts.com/demo/gfx/sun.png)' //链接 ...
- PLSQL Developer 运用Profiler 分析存储过程性能
最近应公司需要,需要编写ORACLE存储过程.本人新手,在完成存储过程的编写后,感觉需要对存储过程中各个语句的执行时间进行分析,以便 对整个存储过程进行优化. 由于用的是PLSQL Developer ...
- 《锋利的JQuery》读书要点笔记4——表格表单的操作
第五章 jQuery对表单,表格的操作以及更多应用 这章主要以一些具体案例讲解了jQuery对表单,表格的常用操作,以及一些常见的jQuery应用,用到的都是上几章说的东西.下面就以具体的案例来展开. ...
- 删除某个ros包之后catkin_make冒错
CMake Error at /home/ubuntu/Workspaces/rosProject/workspace1/devel/share/costmap_2d/cmake/costmap_2d ...
- java 8中撤销永久代,引入元空间
撤销永久代,引入元空间: 在 JDK 1.8 中,HotSpot 已经没有 “PermGen space”这个空间了,取而代之是一个叫做 Metaspace(元空间) 的东西. Java7中已经将字符 ...
- F - Oil Deposits 【地图型BFS+联通性】
The GeoSurvComp geologic survey company is responsible for detecting underground oil deposits. GeoSu ...
- Typora
Typora BB in front 如果你是一个佛(lan)系(duo),内心文艺的程序员,并且你对其他Markdown编辑器的使用效果感觉不是很好的话,可以来了解一下该软件Typora. What ...
- ubuntu 16.04.1 LTS 初始化
gcc环境------------------sudo apt-get update && \sudo apt-get install build-essential software ...