[Functional Programming] Draw Items from One JavaScript Array to Another using a Pair ADT
We want to be able to pick nine random cards from an array of twelve cards, but can run into problems of keeping both the cards already draw and the cards left to draw from. Tracking two bits of state like this can create some hard to maintain argument gymnastics when creating our functions. Luckily we have a datatype Pair at our disposal that allows us to combine two values in to one value.
We will use this Pair type to model both a draw pile and a remaining pile, and take advantage of a couple special properties of Pair that will allow us to combine two Pair instances in a meaningful way by chaining. Just like we have done time and time again with the State ADT.
We have generated array of cards:
[
{ 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' } ]
By the following code:
const {prop,assoc, pick, State, 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;
// #region generateCards
const state = {
colors: [ 'orange', 'green', 'blue', 'yellow' ],
shapes: [ 'square', 'triangle', 'circle' ]
};
const getState = key => get(prop(key))
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
Now what we want to do is split cards array into a Pair,
on the left side pair is the selected card array,
on the rigth side pair is the unselected cards array.
// Splite Cards into two pars
//[Selected Cards] - [UnSelected Cards] const getAt = index => array => array[index];
const unsetAt = index => array => ([...array.slice(, index), ...array.slice(index + )]);
// Deck :: Pair [Card] [Card]
// drawCardAt :: Integer -> [Card] -> Deck
const drawCardAt = index => fanout(
getAt(index),
unsetAt(index)
) console.log(
generateCards()
.map(drawCardAt())
.evalWith(state).fst()
) // { id: 'orange-square', color: 'orange', shape: 'square' } console.log(
generateCards()
.map(drawCardAt())
.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-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' } ]
*/
Here we use 'fanout' to generate a Pair.
Notice that the left side pair is an object, not an array, we need to use 'bimap' to lift left side pair into Array. To do that,. we use 'bimap'
const drawCardAt = index => compose(
bimap(Array.of, identity),
fanout(
getAt(index),
unsetAt(index)
)
) console.log(
generateCards()
.map(drawCardAt())
.evalWith(state).fst()
) // [{ id: 'orange-square', color: 'orange', shape: 'square' }]
---
const {prop,assoc, pick, bimap, State, 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;
// #region generateCards
const state = {
colors: [ 'orange', 'green', 'blue', 'yellow' ],
shapes: [ 'square', 'triangle', 'circle' ]
};
const getState = key => get(prop(key))
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
// Splite Cards into two pars
//[Selected Cards] - [UnSelected Cards]
const getAt = index => array => array[index];
const unsetAt = index => array => ([...array.slice(, index), ...array.slice(index + )]);
// Deck :: Pair [Card] [Card]
// drawCardAt :: Integer -> [Card] -> Deck
const drawCardAt = index => compose(
bimap(Array.of, identity),
fanout(
getAt(index),
unsetAt(index)
)
)
console.log(
generateCards()
.map(drawCardAt())
.map(chain(drawCardAt()))
.map(chain(drawCardAt()))
.map(chain(drawCardAt()))
.evalWith(state).fst()
) /**
[ { id: 'orange-square', color: 'orange', shape: 'square' },
{ id: 'green-square', color: 'green', shape: 'square' },
{ id: 'green-circle', color: 'green', shape: 'circle' },
{ id: 'blue-triangle', color: 'blue', shape: 'triangle' } ]
*/
console.log(
generateCards()
.map(drawCardAt())
.map(chain(drawCardAt()))
.map(chain(drawCardAt()))
.map(chain(drawCardAt()))
.evalWith(state).snd()
)
/**
[ { id: 'orange-triangle', color: 'orange', shape: 'triangle' },
{ id: 'orange-circle', color: 'orange', shape: 'circle' },
{ id: 'green-triangle', color: 'green', shape: 'triangle' },
{ id: 'blue-square', color: 'blue', shape: 'square' },
{ 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' } ]
*/
[Functional Programming] Draw Items from One JavaScript Array to Another using a Pair ADT的更多相关文章
- 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 ...
- JavaScript Functional Programming
JavaScript Functional Programming JavaScript 函数式编程 anonymous function https://en.wikipedia.org/wiki/ ...
- [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 ...
- BETTER SUPPORT FOR FUNCTIONAL PROGRAMMING IN ANGULAR 2
In this blog post I will talk about the changes coming in Angular 2 that will improve its support fo ...
- 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 ...
- [Javascript ] Array methods in depth - sort
Sort can automatically arrange items in an array. In this lesson we look at the basics including how ...
- Sth about 函数式编程(Functional Programming)
今天开会提到了函数式编程,针对不同类型的百年城方式,查阅了一部分资料,展示如下: 编程语言一直到近代,从汇编到C到Java,都是站在计算机的角度,考虑CPU的运行模式和运行效率,以求通过设计一个高效的 ...
- JavaScript Array methods performance compare
JavaScript Array methods performance compare JavaScript数组方法的性能对比 env $ node -v # v12.18.0 push vs un ...
- Beginning Scala study note(4) Functional Programming in Scala
1. Functional programming treats computation as the evaluation of mathematical and avoids state and ...
随机推荐
- 【洛谷】xht模拟赛 题解
前言 大家期待已久并没有的题解终于来啦~ 这次的T1和HAOI2016撞题了...深表歉意...表示自己真的不知情... 天下的水题总是水得相似,神题各有各的神法.--<安娜·卡列妮娜> ...
- python日志模块笔记
前言 在应用中记录日志是程序开发的重要一环,也是调试的重要工具.但却很容易让人忽略.之前用flask写的一个服务就因为没有处理好日志的问题导致线上的错误难以察觉,修复错误的定位也很困难.最近恰好有时间 ...
- HCharts的y轴保留一位和 两位小数
保留一位小数,有一位小数的不变 yAxis : { labels : { formatter : function () { var strVal = ''+this.value ; if (str ...
- win32 sdk列表视图控件(ListCtrl或ListView)资料整理
列表视图控件是一种非常常用的控件,在需要以报表形式显示数据时,列表控件通常是最好的选择,许多专用的数据报表控件,也是在它的基础上派生而来.与树视图类似,列表控件可以由多个子项目组成,可以设置为Icon ...
- selenium+python自动化77-autoit文件上传【转载】
前言 关于非input文件上传,点上传按钮后,这个弹出的windows的控件了,已经跳出三界之外了,不属于selenium的管辖范围(selenium不是万能的,只能操作web上元素).autoit工 ...
- CF 915 D 拓扑排序
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; const int mod = 14285 ...
- HDU 多校1.7
Function Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Others)Total ...
- CodeForces - 990G GCD Counting
Discription You are given a tree consisting of nn vertices. A number is written on each vertex; the ...
- POJ 2068 Nim(博弈论)
[题目链接] http://poj.org/problem?id=2068 [题目大意] 给出两队人,交叉放置围成一圈,每个人能取的石子数有个上限,各不相同 轮流取石头,取到最后一块石头的队伍算输,问 ...
- 【并查集】【set】AtCoder - 2159 - 連結 / Connectivity
Problem Statement There are N cities. There are also K roads and L railways, extending between the c ...