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的更多相关文章

  1. 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 ...

  2. JavaScript Functional Programming

    JavaScript Functional Programming JavaScript 函数式编程 anonymous function https://en.wikipedia.org/wiki/ ...

  3. [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 ...

  4. 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 ...

  5. 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 ...

  6. [Javascript ] Array methods in depth - sort

    Sort can automatically arrange items in an array. In this lesson we look at the basics including how ...

  7. Sth about 函数式编程(Functional Programming)

    今天开会提到了函数式编程,针对不同类型的百年城方式,查阅了一部分资料,展示如下: 编程语言一直到近代,从汇编到C到Java,都是站在计算机的角度,考虑CPU的运行模式和运行效率,以求通过设计一个高效的 ...

  8. JavaScript Array methods performance compare

    JavaScript Array methods performance compare JavaScript数组方法的性能对比 env $ node -v # v12.18.0 push vs un ...

  9. Beginning Scala study note(4) Functional Programming in Scala

    1. Functional programming treats computation as the evaluation of mathematical and avoids state and ...

随机推荐

  1. Mac自带的SSH客户端

    https://segmentfault.com/q/1010000002806469 还能设置连接成持久连接,方便使用: ttps://www.zhihu.com/question/20541129 ...

  2. PHP定时执行

    参考一 test.bat D:\myamp\php\php.exe -q D:\myamp\Apache\htdocs\dingshi.php dingshi.php <?php ignore_ ...

  3. poj 1696(极角排序)

    Space Ant Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 3924   Accepted: 2457 Descrip ...

  4. MATLAB求函数零点与极值

    1.      roots函数 针对多项式求零点(详见MATLAB多项式及多项式拟合) 2.      fzero函数 返回一元函数在某个区间内的的零点. x0 = fzero(@(x)x.^2-3* ...

  5. Codeforces 608 A. Saitama Destroys Hotel

      A. Saitama Destroys Hotel   time limit per test 1 second memory limit per test 256 megabytes input ...

  6. DP(悬线法)+二维前缀和【p2706】巧克力

    Background 王7的生日到了,他的弟弟准备送他巧克力. Description 有一个被分成n*m格的巧克力盒,在(i,j)的位置上有a[i,j]块巧克力.就在送出它的前一天晚上,有老鼠夜袭巧 ...

  7. 队列 P1160 队列安排(啊啊 不会啊)

    洛谷 题目描述 一个学校里老师要将班上N个同学排成一列,同学被编号为1-N,他采取如下的方法: 1.先将1号同学安排进队列,这时队列中只有他一个人: 2.2-N号同学依次入列,编号为i的同学入列方式为 ...

  8. 第3天-DIV+CSS布局

    盒子模型 margin 设置外边距宽度 有4个值的时候: maigin 10px 5px 15px 20px; (上.右.下.左)有3个值的时候: margin: 10px 5px 15px; (上. ...

  9. 20、Django实战第20天:课程详情页

    1.把course-detail.html复制到templates目录下 2.编辑course-detail.html,分析页面,继承base.html 3.编辑courses.views .... ...

  10. 【分块】bzoj3226 [Sdoi2008]校门外的区间

    题解见 : http://blog.csdn.net/iamzky/article/details/41088151 ORZ ZKY 2个懒标记:是否翻转,覆盖成了什么. 怎么处理一个块上有两个标记的 ...