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

  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. Beginning Scala study note(4) Functional Programming in Scala

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

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

  4. Functional Programming without Lambda - Part 2 Lifting, Functor, Monad

    Lifting Now, let's review map from another perspective. map :: (T -> R) -> [T] -> [R] accep ...

  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. Functional programming

    In computer science, functional programming is a programming paradigm, a style of building the struc ...

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

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

  9. Source insight 3572安装和版本号An invalid source insight serial number was detected解

    Source insight最新版本3572 下载链接:http://www.sourceinsight.com/down35.html,   http://www.sourceinsight.com ...

随机推荐

  1. HDU 4123 Bob’s Race(树形DP,rmq)

    Bob’s Race Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  2. delphi dxRibbon中 F10快捷键不好用的原因

    最近在项目中使用ribbon  ,用F10做快捷键,但是不好用, 不好用的原因是dxBarManager1 中的有个选项UseF10ForMenu, 把这项关闭就可以了

  3. nil coalescing operator

    nil coalescing operator ?? 就是 optional和 三元运算符?:的简写形式. 比如一个optional String类型的变量 var a:String? // prin ...

  4. Nginx rewrite URL examples with and without redirect address

    原文地址: http://www.claudiokuenzler.com/blog/436/nginx-rewrite-url-examples-with-without-redirect-addre ...

  5. 【C++】拷贝构造函数和赋值符函数

    在C++中,调用拷贝构造函数有三种情况: 1.一个对象作为函数参数,以值传递的方式传入函数体. 2.一个对象作为函数返回值,以值传递的方式从函数返回. 3.一个对象用于给另外一个对象进行初始化(复制初 ...

  6. Linux学习2-在阿里云服务器上部署禅道环境

    前言 以前出去面试总会被问到:测试环境怎么搭建?刚工作1-2年不会搭建测试环境还可以原谅自己,工作3-5年后如果还是对测试环境搭建一无所知,面试官会一脸的鄙视. 本篇以最简单的禅道环境搭建为例,学习下 ...

  7. Exchange2003/2010共存模式环境迁移

    一.我司的exchange2010架构设计基于中心的模式进行.而且基于exchange2010sp3进行. 基于dag三台架构设计进行,截止到5月14日,北京局基于2台dag进行,大连局基于excha ...

  8. C#学习笔记:预处理指令

    C#和C/C++一样,也支持预处理指令,下面我们来看看C#中的预处理指令. #region 代码折叠功能,配合#endregion使用,如下: 点击后如下: 条件预处理 条件预处理可以根据给出的条件决 ...

  9. java项目实现流水号自动增长

    项目中有一个规则编号字段,从1开始,编号长度为5位,那么第一条数据编号就是00001. 实现的基本思路就是项目启动时,从数据库获取当前最大值,作为静态变量存储: 业务获取新的编码,考虑并发问题,获取编 ...

  10. Office Web Apps 错误日志

    前言 最近一直在用Office Web Apps,使用过程会有各种各样的错误,众所周知,sharepoint的错误都在15/Logs下面保存错误日志,那么OWA呢? 经过查找,发现Office Web ...