presented by Bill Kidwell
Functional programming is about functions without side effects
Definition adapted from Mary Rose Cook
var a = 0;
function increment() {
a+=1;
}
function increment(a) {
return a+1;
}
A practical functional library for JavaScript programmers.
The name?
They like sheep.
const double = x => x * 2;
R.map(double, [1,2,3]); //=> [2,4,6]
[1,2,3].map(double); //=> [2,4,6]
... or map over an object
const data = { a: 1, b: 2, c: 3 };
R.map(double, data); //=> { a: 2, b: 4, c: 6 }
const array = [1,2,3];
const sum = R.reduce(R.add, 0, array); // => 6
var acc = 0;
acc = R.add(acc, array[0]); // => 0 + 1 = 1
acc = R.add(acc, array[1]); // => 1 + 2 = 3
acc = R.add(acc, array[2]); // => 3 + 3 = 6
return acc; // => 6
// R.reduce( function, accumulator, list)
const sum = R.reduce(R.add, 0, array);
Find the max of an array using reduce and R.max(a,b)
const max = R.reduce(R.max, Number.MIN_VALUE, array);
Find the min of an array using reduce and R.min(a,b)
const min = R.reduce(R.min, Number.MAX_VALUE, array);
Are map and reduce really better than a for loop?
One place they shine is with filter/reject
const isEven = x => x % 2 === 0;
R.filter(isEven, [1, 2, 3, 4]); // => [2, 4]
R.reject(isEven, [1, 2, 3, 4]); // => [1, 3]
const sales = [
{ category: "Elite", customer: "Eric", amount: 34.99 },
{ category: "Delux", customer: "Doug", amount: 39.99 },
{ category: "Delux", customer: "Drake", amount: 39.99 },
{ category: "Lite", customer: "Lewis", amount: 29.99 },
{ category: "Elite", customer: "Eleanor", amount: 34.99 },
{ category: "Delux", customer: "Dakota", amount: 39.99 },
{ category: "Plus", customer: "Paul", amount: 24.99 },
{ category: "Elite", customer: "Ellen", amount: 34.99 },
{ category: "Basic", customer: "Bob", amount: 12.99 },
{ category: "Delux", customer: "David", amount: 39.99 },
{ category: "Lite", customer: "Linda", amount: 29.99 },
{ category: "Plus", customer: "Pauline", amount: 24.99 },
{ category: "Delux", customer: "Diego", amount: 39.99 },
{ category: "Lite", customer: "Lenny", amount: 29.99 },
{ category: "Elite", customer: "Edward", amount: 34.99 }
];
const firstSale = sales[0], secondSale = sales[1];
const isCategory = (cat, object) =>
R.prop('category', object) === cat;
isCategory('Elite', firstSale); // => true
isCategory('Elite', secondSale); // => false
const isCategory = R.curry(
( cat, object ) => R.prop('category', object) === cat
);
const isElite = isCategory("Elite");
const isDelux = isCategory("Delux");
isElite(firstSale); // => true
isDelux(firstSale); // => false
const isCategory = function(cat) {
return function (object) {
return R.prop('category', object) === cat;
}
}
const isElite = isCategory('Elite');
isElite(firstSale); // => true
isElite(secondSale); // => false
const eliteSales = R.filter(isElite, sales);
// => [
// { category: "Elite", customer: "Eric", amount: 34.99 },
// { category: "Elite", customer: "Eleanor", amount: 34.99 },
// { category: "Elite", customer: "Ellen", amount: 34.99 },
// { category: "Elite", customer: "Edward", amount: 34.99 }
// ]
const deluxSales = R.filter(isDelux, sales);
// => [
// { category: "Delux", customer: "Doug", amount: 39.99 },
// { category: "Delux", customer: "Drake", amount: 39.99 },
// { category: "Delux", customer: "Dakota", amount: 39.99 },
// { category: "Delux", customer: "David", amount: 39.99 },
// { category: "Delux", customer: "Diego", amount: 39.99 }
// ]
// # of sales
R.length(eliteSales); // 4
// Total of sales
const getSalesAmounts = R.map(R.prop("amount"));
const eliteSalesAmounts
= getSalesAmounts(eliteSales); // => [34.99, 34.99, 34.99, 34.99]
const sum = R.reduce(R.add, 0);
sum(eliteSalesAmounts); // 139.96
// Filter the array to the items with that category
const filterByCategory =
(category, objects) => R.filter(
isCategory(category), objects);
// Get the array of sale amounts
const getSalesAmounts = R.map(R.prop("amount"));
// And sum it
const sum = R.reduce(R.add, 0);
const calculateTotal = R.pipe(
filterByCategory,
getSalesAmounts,
sum
);
calculateTotal("Elite", sales);
var result1 =
filterByCategory("Elite", sales) // => List of all elite sales
var result2 = getSalesAmounts(result1); // => Array of all amounts
sum(result2); // => 139.96
//Which is equivalent to...
sum( getSalesAmounts( filterByCategory("Elite",sales) ) );
R.groupBy( R.prop("category"), sales );
{
Basic: [
{ category: "Basic", customer: "Bob", amount: 12.99 }
],
Delux: [
{ category: "Delux", customer: "Doug", amount: 39.99 }, ...
],
Elite: [
{ category: "Elite", customer: "Eric", amount: 34.99 }, ...
],
...
}
// Group sales by category
const groupSales = R.groupBy(R.prop("category"))
// For a category, sumPrices
const sumPrices = R.pipe( getSalesAmounts, sum );
// In one function
const allTotals = R.pipe(
groupSales,
R.map( sumPrices )
)
allTotals(sales);
{
Basic: 12.99,
Delux: 199.95000000000002,
Elite: 139.96,
Lite: 89.97,
Plus: 49.98
}
var labelArray = ['Basic', 'Plus', 'Lite', 'Elite', 'Delux'];
var valueArray = [1,2,3,4,5];
var result = R.zipObj(labelArray, valueArray);
{
"Basic": 1,
"Plus": 2,
"Lite": 3,
"Elite": 4,
"Delux": 5
}
const getLengths =
arrayObj => R.map(R.length, arrayObj);
var arrayData = {
label: ["Basic", "Plus", "Lite", "Elite",
"Delux", "Oops", "Uh Oh"],
value: [1, 2, 3, 4, 5],
color: d3.schemeSet1
};
getLengths(arrayData); // => { label: 7, value: 5, color: 10 }
// To get the values of the object
R.values(lengthObj); // => [7,5,10]
const getMinOfObject =
lengthObj =>
R.reduce(R.min, Number.MAX_VALUE, R.values(lengthObj));
// => 5
const obj = {a: 2, b: 4, c: 6};
// Get the keys
R.keys(obj); // => ['a', 'b', 'c']
// Get the values
R.values(obj); // => [2, 4, 6]
Instead of determining which array was smallest...
R.range(0, 5); // => [0,1,2,3,4]
const getIndexes
= R.pipe(
getLengths,
getMinOfObject,
R.range(0)
);
const getNth = R.curry(
(arrayObj, n) => R.map( R.nth(n), arrayObj )
);
getNth(arrayData, 0);
// => {label:"Basic", value: 1, color:"#e41a1c"},
function zipArrays( arrayObj ) {
var indexes = getIndexes(arrayObj);
return R.map(getNth(arrayObj), indexes);
}
Randy Coulman's series Thinking in Ramda
Eric Elliot's series Composing Software
Professor Frisby's Mostly Adequate Guide to Functional Programming by Brian Lonsdorf (aka Dr. Boolean)