1 + 2 R.add(1)(2) Maybe.Just(1).ap(Maybe.Just(2).map(R.add)).just();
https://www.reddit.com/r/ProgrammerHumor/comments/6d3eqh/functional_programming_for_beginners/
Functional Programming
Please, don't make things overcomplicated
🙏
Pure / Impure
const x = 1;
const y = 2;
const impureFunction = () => x + y;
const pureFunction = (x, y) => x + y;
Pure / Impure
const a = {b: 1};
const impureFunction = () => a.b++;
const impureFunctionEither = (a) => a.b++;
const pureFunction = (a) =>
Object.assign({}, a, {b: a.b + 1});
Pure / Impure
const a = {b: 1};
const impureFunction = () => a.b++;
const impureFunctionEither = (a) => {
a.b++;
return a;
}
const pureFunction = (a) =>
Object.assign({}, a, {b: a.b + 1});
Mutations
const a = {b: 1};
// mutation
a.b = 2;
[1, 3, 2].sort();
// immutable
const c = Object.assign({}, a, {b: 3});
const newArr = [1, 2, 3].map(x => x * 2);
Currying
Currying
const add = (a) => (b) => a + b;
add(1)(5) === 6;
const dbSaver = (dbConnection) =>
(obj) => dbConnection.save(obj);
const save = dbBuilder(db);
save({city: "Wrocław"});
save({city: "Poznań"});
Ramda?
246
Curried helpers
What is Ramda?
Curry
const addFn = (a, b, c) => a + b + c;
const curriedAddFn = R.curry(addFn);
curriedAddFn(1, 2)(3); // 6
['3', '3', '3', '3'].map(parseInt);
// [3, NaN, NaN, NaN]
const prsInt = R.curry(parseInt)(R.__, 10);
['3', '3', '3', '3'].map(prsInt);
// [3, 3, 3, 3]
const prsInt = (val) => parseInt(value, 10);
['3', '3', '3', '3'].map(prsInt);
// [3, 3, 3, 3]
R.__
Conditional
All and Equals
if (var1 === true
&& var2 === true
&& var3 === true
&& var4 === true) {
...
}
const var1 = 1;
const var2 = [1]
if (var1 && var2) {
console.log('coercion loves you ;)');
};
All and Equals
const isTruthy = R.equals(true);
R.all(isTruthy)([var1, var2, var3, var4]);
Both
const min = R.gte(R.__, 0);
const max = R.lte(R.__, 100);
const isPercent = R.both(min, max);
isPercent(10); // true
isPercent(-1); // false
isPercent(101); // false
Both
const notCat = (x) => x !== 'dog';
const notDog = (x) => x !== 'cat';
const isNotCatAndSeal = R.both(notCat, notDog);
isNotCatAndSeal('seal'); // true
isNotCatAndSeal('dog'); // false
allPass
const isDeveloper = R.propEq('role', 'developer');
const isLocatedWroclaw = R.propEq('location', 'Wroclaw');
const isGonnaBeHired = R.allPass(
[isDeveloper, isLocatedWroclaw]
);
isGonnaBeHired({role: 'Developer', location: 'Berlin'});
//=> false
isGonnaBeHired({role: 'Developer', location: 'Wroclaw'});
//=> true
Apply
const maxNum = R.apply(Math.max, R.__);
maxNum([1, 5, 3]); // 5
maxNum([9, 9, 3]); // 9
Deep clone, merge
countBy
const numbers = [1.0, 1.1, 2.0, 3.0, 2.2];
R.countBy(Math.floor)(numbers);
//=> {'1': 2, '2': 2, '3': 1}
const letters = ['a', 'b', 'A'];
R.countBy(R.toLower)(letters);
//=> {'a': 2, 'b': 1}
defaultTo
const valOrNa = R.defaultTo('n/a');
defaultTo42(null); //=> 'n/a'
defaultTo42(undefined); //=> 'n/a'
defaultTo42('Hey there!'); //=> 'Hey there!'
defaultTo42(NaN); //=> 'n/a'
DropRepeats 😉
R.dropRepeats([1, 1, 2, 4, 4, 2]); //=> [1, 2, 4, 2]
eqProps
const o1 = { a: 3, b: 2, c: 3 };
const o2 = { a: 1, b: 'c', c: 3 };
R.eqProps('a', o1, o2); //=> false
R.eqProps('c', o1, o2); //=> true
Deeper
Evolve
const obj = {
firstName: ' johny ',
data: {
elapsed: 100,
remaining: 1400
},
id:123
};
const transformations = {
firstName: R.pipe(R.trim, R.toUpper),
lastName: R.trim,
data: {
elapsed: R.add(1),
remaining: R.add(-1)
}
};
R.evolve(transformations, obj);
Lenses
Inner Join
R.innerJoin(
(record, id) => record.id === id,
[{id: 824, name: 'Richie Furay'},
{id: 956, name: 'Dewey Martin'},
{id: 313, name: 'Bruce Palmer'},
{id: 456, name: 'Stephen Stills'},
{id: 177, name: 'Neil Young'}],
[177, 456, 999]
);
//=> [
{id: 456, name: 'Stephen Stills'},
{id: 177, name: 'Neil Young'}
]
Project
const user1 = {
name: 'Jack',
comments: 50,
posts: 1
};
const user2 = {
name: 'Fred',
comments: 12,
posts: 14
};
R.project(['name', 'posts'], [user1, user2]); //=>
[{name: 'Jack', posts: 1}, {name: 'Fred', posts: 14}]
R.project(['name', 'posts'], [user1, user2]);
SELECT name, posts FROM users;
Path 😍 (kinda Elvis Operator)
R.path(['a', 'b'], {a: {b: 2}});
PathOr
R.pathOr('N/A', ['a', 'b'], {a: {b: 2}});
Pipes
Pipe
const data = [
{a: { b: 5.12 } },
{a: { b: 7.1102 } }
];
const dataDiss = R.pathOr(0, ['a', 'b'], R.__);
const test1 = dataDiss({a: { b: 5.12 }});
const dataPipe = R.pipe(dataDiss, Math.floor, x => x * 2);
const res = data.map(dataPipe); // [10, 14]
Difference?
const dataPipe = R.pipe(dataDiss, Math.floor, x => x * 2);
const res = data.map(dataPipe);
// [10, 14]
const res = data
.map(dataDiss)
.map(Math.floor)
.map(x => x * 2);
// [10, 14]
R.propOr
const alice = {
name: 'ALICE',
age: 101
};
const favorite = R.prop('favoriteLibrary');
const favoriteWithDefault =
R.propOr('Ramda', 'favoriteLibrary');
favorite(alice); //=> undefined
favoriteWithDefault(alice); //=> 'Ramda'
Flatten
R.flatten([1, 2, [3, 4], [5, [6, [7, 8], 9]]]);
// [1, 2, 3, 4, 5, 6, 7, 8, 9];
Overlaps with lodash / underscore
Questions?
Send me a Pigeon