[Functional Programming] Running though a serial number prediction functions for tagging, pairing th

Posted answer1215

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Functional Programming] Running though a serial number prediction functions for tagging, pairing th相关的知识,希望对你有一定的参考价值。

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, -1), flip(lte, 50));
const getMedPred = and(flip(gt, 50), flip(lte, 100));
const getLrgPred =  flip(gt, 100);
// taggedPred :: (b, (a -> Boolean))
// taggedPreds :: [taggedPred]
const taggedPreds = [
    [Sml, getSmlPred],
    [Med, getMedPred],
    [Lrg, getLrgPred]
];

So if we have input as:

15 -> Sml;
60 -> Med
101 -> Lrg

Also we wish our program to the safe, we want:

-1 -> 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, -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]
];
// tagValue :: taggedPred -> a -> Maybe b
const tagValue = curry(([tag, pred]) => compose(
    map(constant(tag)),
    safe(pred)
));    

console.log(40 - Sml, tagValue(taggedPreds[0], 40)); // Just "Sml"
console.log(60 - Med, tagValue(taggedPreds[1], 60)); // Just "Med"
console.log(101 - Lrg, tagValue(taggedPreds[2], 101)); // Just "Lrg"
console.log(-1 - Nothing, tagValue(taggedPreds[0], -5)); // 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(49)); // 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(49)); // Pair( "Sml", { number: 49 } )

 

Lastly, we want to have the final result as:

const cardFromNumber = compose(
    merge(assoc(type)),
    tagCard
);

console.log(
    cardFromNumber(101)
) // { 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, -1), flip(lte, 50));
const getMedPred = and(flip(gt, 50), flip(lte, 100));
const getLrgred =  flip(gt, 100);
// 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(101)
) // { 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(/^30[0-5]/)],
    [Diners|diners, test(/^(30[6-9]|36|38)/)],
    [JCB|jcb, test(/^32(2[89]|[3-8][0-9])/)],
    [AMEX|american-express, test(/^3[47]/)],
    [Visa Electron|visa, test(/^(4026|417500|4508|4844|491(3|7))/)]
]
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, -1), flip(lte, 50));
const getMedPred = and(flip(gt, 50), flip(lte, 100));
const getLrgred =  flip(gt, 100);
// 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 th的主要内容,如果未能解决你的问题,请参考以下文章

[Functional Programming ADT] Debug a Functional JavaScript composeK Flow

Functional programming

Functional Programming.

[Functional Programming] Monad

Functional programming-函数式编程

python learning Functional Programming.py