[Functional Programming] Running though a serial number prediction functions for tagging, pairing the result into object
Let's we have some prediction functions, for each prediction function has a corresponding tag:
const {gt, lte, gte, lt} = require('ramda');
const {flip} = require('crocks');
const getSmlPred = and(flip(gt, -), flip(lte, ));
const getMedPred = and(flip(gt, 50), flip(lte, ));
const getLrgPred = flip(gt, );
// taggedPred :: (b, (a -> Boolean))
// taggedPreds :: [taggedPred]
const taggedPreds = [
['Sml', getSmlPred],
['Med', getMedPred],
['Lrg', getLrgPred]
];
So if we have input as:
-> 'Sml';
-> 'Med'
-> 'Lrg'
Also we wish our program to the safe, we want:
- -> Nothing
We can write a quick test function:
const {gt, lte, gte, lt} = require('ramda');
const {First, mreduceMap, and, safe, option, flip, objOf, assoc, not,
merge, identity, fanout, curry, compose, map, constant} = require('crocks');
const getSmlPred = and(flip(gt, -1), flip(lte, 50));
const getMedPred = and(flip(gt, 50), flip(lte, 100));
const getLrgred = flip(gt, 50);
// taggedPred :: (b, (a -> Boolean))
// taggedPreds :: [taggedPred]
const taggedPreds = [
['Sml', getSmlPred],
['Med', getMedPred],
['Lrg', getLrgred]
];
const fn = curry(([tag, pred]) => x => safe(pred)(x)
.map(constant(tag)));
console.log('40 - Sml', fn(taggedPreds[0], 40)); // Just "Sml"
console.log('60 - Med', fn(taggedPreds[1], 60)); // Just "Med"
console.log('101 - Lrg', fn(taggedPreds[2], 101)); // Just "Lrg"
We can refactor the code into a more pointfree style and rename the testing 'fn' to 'tagValue':
const {gt, lte, gte, lt} = require('ramda');
const {First, mreduceMap, and, safe, option, flip, objOf, assoc, not,
merge, identity, fanout, curry, compose, map, constant} = require('crocks');
const getSmlPred = and(flip(gt, -), flip(lte, ));
const getMedPred = and(flip(gt, 50), flip(lte, ));
const getLrgred = flip(gt, );
// taggedPred :: (b, (a -> Boolean))
// taggedPreds :: [taggedPred]
const taggedPreds = [
['Sml', getSmlPred],
['Med', getMedPred],
['Lrg', getLrgred]
];
// tagValue :: taggedPred -> a -> Maybe b
const tagValue = curry(([tag, pred]) => compose(
map(constant(tag)),
safe(pred)
));
console.log('40 - Sml', tagValue(taggedPreds[], )); // Just "Sml"
console.log('60 - Med', tagValue(taggedPreds[], )); // Just "Med"
console.log('101 - Lrg', tagValue(taggedPreds[], )); // Just "Lrg"
console.log('-1 - Nothing', tagValue(taggedPreds[], -)); // Nothing "Nothing"
Now, what we want is create fews functions, we know that we want data comes last, we want to partiaclly apply the predcitions functions.
// match :: [ taggedPreds ] -> a -> Maybe b
const match =
flip(x => mreduceMap(First, flip(tagValue, x)));
const matchNumber = match(taggedPreds);
console.log('matchNumber', matchNumber()); // Just "Sml"
'mreduceMap': it take Monoid for combine the data together, here we use 'First', so only take the first Maybe result.
Then for each [tag, pred], we will run with tagValue([tag, pred], x), because [tag, pred] will be partiaclly applied last, but 'tagValue' function takes it as first arguement, so we have to use 'flip'. And apply 'x' first.
In the test code above, we get ''Just Sml" back for number 49. It is good, but not enough, what we really want is keeping a Pair(a, s), for example: Pair('Sml', 40); we can keep the original state together with the tag result.
What we can do is using 'fanout', which take two functions and generate a Pair:
const tagCard = fanout(compose(option(' | '), matchNumber), objOf('number'));
console.log('tagCard', tagCard()); // Pair( "Sml", { number: 49 } )
Lastly, we want to have the final result as:
const cardFromNumber = compose(
merge(assoc('type')),
tagCard
); console.log(
cardFromNumber()
) // { number: 101, type: 'Lrg' }
Full Code:
---
const {gt, lte} = require('ramda');
const {First, mreduceMap, and, safe, option, flip, objOf, assoc,
merge, fanout, curry, compose, map, constant} = require('crocks');
const getSmlPred = and(flip(gt, -), flip(lte, ));
const getMedPred = and(flip(gt, ), flip(lte, ));
const getLrgred = flip(gt, );
// taggedPred :: (b, (a -> Boolean))
// taggedPreds :: [taggedPred]
const taggedPreds = [
['Sml', getSmlPred],
['Med', getMedPred],
['Lrg', getLrgred]
];
// tagValue :: taggedPred -> a -> Maybe b
const tagValue = curry(([tag, pred]) => compose(
map(constant(tag)),
safe(pred)
));
// match :: [ taggedPreds ] -> a -> Maybe b
const match =
flip(x => mreduceMap(First, flip(tagValue, x)));
const matchNumber = match(taggedPreds);
const tagCard = fanout(compose(option(' | '), matchNumber), objOf('number'));
const cardFromNumber = compose(
merge(assoc('type')),
tagCard
)
console.log(
cardFromNumber()
) // { number: 101, type: 'Lrg' }
---
This coding partten is useful, because we can keep the structure, just replace the tags and predications functions:
// data.js
const {test} = require('ramda'); module.exports = [
['Diners - Carte Blanche|diners', test(/^[-]/)],
['Diners|diners', test(/^([-]||)/)],
['JCB|jcb', test(/^([]|[-][-])/)],
['AMEX|american-express', test(/^[]/)],
['Visa Electron|visa', test(/^(||||(|))/)]
]
const {gt, lte} = require('ramda');
const {First, mreduceMap, and, safe, option, flip, objOf, assoc,
merge, fanout, curry, compose, map, constant} = require('crocks');
const getSmlPred = and(flip(gt, -), flip(lte, ));
const getMedPred = and(flip(gt, ), flip(lte, ));
const getLrgred = flip(gt, );
// taggedPred :: (b, (a -> Boolean))
// taggedPreds :: [taggedPred]
const taggedPreds = require('./data.js');
// tagValue :: taggedPred -> a -> Maybe b
const tagValue = curry(([tag, pred]) => compose(
map(constant(tag)),
safe(pred)
));
// match :: [ taggedPreds ] -> a -> Maybe b
const match =
flip(x => mreduceMap(First, flip(tagValue, x)));
const matchNumber = match(taggedPreds);
const tagCard = fanout(compose(option(' | '), matchNumber), objOf('number'));
const cardFromNumber = compose(
merge(assoc('type')),
tagCard
)
console.log(
cardFromNumber('4026-xxxx-xxxxx-xxxx')
) // { number: '4026-xxxx-xxxxx-xxxx', type: 'Visa Electron|visa' }
[Functional Programming] Running though a serial number prediction functions for tagging, pairing the result into object的更多相关文章
- 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 ...
- Beginning Scala study note(4) Functional Programming in Scala
1. Functional programming treats computation as the evaluation of mathematical and avoids state and ...
- 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 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 ...
- Functional programming
In computer science, functional programming is a programming paradigm, a style of building the struc ...
- Source insight 3572版本安装及An invalid source insight serial number was detected解决方法
Source insight有最新版3572.3.50.0076 下载连接:http://www.sourceinsight.com/down35.html, http://www.sourcei ...
- Volume serial number could associate file existence on certain volume
When it comes to lnk file analysis, we should put more emphasis on the volume serial number. It coul ...
- Source insight 3572安装和版本号An invalid source insight serial number was detected解
Source insight最新版本3572 下载链接:http://www.sourceinsight.com/down35.html, http://www.sourceinsight.com ...
随机推荐
- LightOJ 1366 - Pair of Touching Circles (统计矩形内外切圆对)
1366 - Pair of Touching Circles PDF (English) Statistics Forum Time Limit: 3 second(s) Memory Limi ...
- 怎样把XP系统装到USB里?
怎么样在usb(usb闪存)里面装XP系统? 就是把usb当硬盘用 不买硬盘. U盘肯定装不了系统,装进去了也肯定蓝屏.为什么?因为USB得数据传输太慢,不会超过10M/S的,而你的IDE口或者SAT ...
- PHP扩展迁移为PHP7扩展兼容性问题记录
PHP7扩展编写的时候,提供的一些内核方法和之前的PHP之前的版本并不能完全兼容.有不少方法参数做了调整.下面是在迁移过程中遇到的一些问题.记录下来,避免大家再踩坑. add_assoc_string ...
- Mustache.js语法
看了Mustache的github,学学此中的语法,做个笔记 1.简单的变量调换:{{name}} 1 var data = { "name": "Willy" ...
- Windows Phone本地数据库(SQLCE):8、DataContext(翻译)
这是“windows phone mango本地数据库(sqlce)”系列短片文章的第八篇. 为了让你开始在Windows Phone Mango中使用数据库,这一系列短片文章将覆盖所有你需要知道的知 ...
- activity_main.xml 要用 Android Common XML Editor打开,双击的方式直接跳转到浏览器了
- Mac上 python 找不到 yaml模块
(1) yaml http://codyaray.com/2011/12/pyyaml-using-easy_install-on-mac-os-x-lion 1.报错 ImportError: N ...
- webrtc在ubuntu14.04上的编译过程(12.04亦可)
转自:http://blog.csdn.net/xiangjai/article/details/44409751 一.虚拟机环境搭建 1.安装ubuntu 14.04虚拟机: 因为可以屏蔽svn版本 ...
- 实用ExtJS教程100例-005:自定义对话框Ext.MessageBox.show
我们对ExtJS对话框进行了三篇演示: MessageBox的三种用法 进度条对话框Ext.MessageBox.progress 等待对话框Ext.MessageBox.wait 通过上面三篇内容的 ...
- DataGridView设置列标题不换行
dgv.ColumnHeadersDefaultCellStyle.WrapMode = DataGridViewTriState.False; //设置列标题不换行 // 设定包括Header和所 ...