[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 ...
随机推荐
- 4.flume实战(一)
需求:从指定网络端口采集数据输出到控制台 使用flume的关键就是写配置文件 a)配置source b)配置channel c)配置sink d)把以上三个组件串起来 我们看一下官网给的配置文件 # ...
- 关于transform的属性
transfrom的出现让许多静态的东西动了起来,让网页更加具有生命力. 在transform属性中,transform-origin属性仅是其中之一,要彻底理解transform属性,这是不够的,必 ...
- SQL按多个字段排序时的实现规则
1.在使用SQL中的ORDER BY按照表中的多个列对表做排序是,会按照第一个列的排序条件作为排序基准,当第一个列的值都相同时,才会按照后面的列的排序条件作为排序基准: 案例如下: 图一和图二展示的是 ...
- selenium+python自动化77-autoit文件上传【转载】
前言 关于非input文件上传,点上传按钮后,这个弹出的windows的控件了,已经跳出三界之外了,不属于selenium的管辖范围(selenium不是万能的,只能操作web上元素).autoit工 ...
- Django基础之视图
Django的View(视图) 一个视图函数(类),简称视图,是一个简单的Python 函数(类),它接受Web请求并且返回Web响应. 响应可以是一张网页的HTML内容,一个重定向,一个404错误, ...
- 对数据访问层的重构(及重构中Perl的应用)
以前上学的时候,听到“一个学生在毕业后刚刚开始编程的头几年中,写出的代码多半是垃圾”这样的说法,均不屑一顾.现在工作一年多了,越发感觉自己代码中疏漏处甚多,故近来常做亡羊补牢的重构之举.拿自己4个月前 ...
- CURL命令的使用
原文地址:http://blog.sina.com.cn/s/blog_4b9eab320100slyw.html 可以看作命令行浏览器 1.开启gzip请求curl -I http://www.si ...
- win上安装Redis并将其设置为服务
win上安装Redis并将其设置为服务 redis下载地址:https://redis.io/ 或者在下面的地址下载 https://github.com/zhangxy1035/redisDownl ...
- js中OOP小指南
js中OOP小指南 在指南中,我将尝试解析以面向对象规范聚焦的es6的新特性. 首先, 什么是设计模式 范例是某个事务的例子或模型,在某种情况下,按照一种模式创建了计算机程序. 什么是面向对象 显然你 ...
- 2017中国大学生程序设计竞赛 - 女生专场B【DP】
B HDU - 6024 [题意]:n个教室,选一些教室建造糖果商店. 每个教室,有一个坐标xi和在这个教室建造糖果商店的花费ci. 对于每一个教室,如果这个教室建造糖果商店,花费就是ci,否则就是与 ...