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. go语言实现拷贝文件

    package main import ( "fmt" "io" "os" ) func main(){ list := os.Args / ...

  2. 使用System.getProperty("line.separator")时没有换行问题解决

    项目中要实现替换模版txt文本里面的内容,然后生成新的文档,其中先把模版文本的内容通过创建的 BufferedReader bufReader 使用 readLine() 来一行一行读取,所以在完成替 ...

  3. HTML布局相关的CSS样式属性

    # 转载请留言联系 注意,样式属性是写进CSS里面的. 布局常用样式属性: width 设置元素(标签)的宽度,如:width:100px; height 设置元素(标签)的高度,如:height:2 ...

  4. Idea设置全白色 背景

    IDEA设置全白色背景 标签(空格分隔): 工具使用 编辑框白色设置 菜单栏白色设置

  5. hdu 3666(差分约束,手动栈解决超时问题)

    THE MATRIX PROBLEM Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...

  6. C++指针和数组的区别(不能混用的情况)

    通常情况下,C++中指针和数组是可以混用的,但是,在编写字符数组的全排列的时候,混用却出了问题,因此,今天特地mark一下,以备日后查找 这里整理的,不包括用new开辟的动态数组 1.数组一旦声明,我 ...

  7. Cocos2dx-Lua UIScrollView 和 UITableView 对比

    为什么写这个 上面这个问题的答案也是我写这篇文章的初衷,在最近给游戏添加一些列表的时候,对比着应用了一下他们两个,在它们两个之间的优劣势之间进行取舍,就有了这个问题的答案. 按照我一个iOS开发而言, ...

  8. Dfs【p4306(bzoj 2208)】 [JSOI2010]连通数

    Description 度量一个有向图恋情情况的一个指标是连通,指途中可达点对的个数. 下图的连通数是14 现在要你求出连通数 Input 输入数据第一行是图顶点的数量,一个正整数N. 接下来N行,每 ...

  9. [Lydsy1805月赛] 对称数

    挺不错的一道数据结构题QWQ. 一开始发现这个题如果不看数据范围的话,妥妥的树上莫队啊23333,然鹅10组数据是不可能让你舒舒服服的树上莫队卡过的23333 于是想了想,这个题的模型就是,把u到v链 ...

  10. [Contest20171028]火神的鱼

    火神最爱的就是吃鱼了,所以某一天他来到了一个池塘边捕鱼.池塘可以看成一个二维的平面,而他的渔网可以看成一个与坐标轴平行的矩形.池塘里的鱼不停地在水中游动,可以看成一些点.有的时候会有鱼游进渔网,有的时 ...