Meet Ramda, a functional programming helper library which can replace Lodash and Underscore in various use-cases. Ramda is all curried and adds various facilities for increasing code reuse.
10. Globalcode – Open4education
Meet Ramda
Emphasizes a purer functional style
Immutability and side-effect free functions
Ramda functions are automatically curried
Argument ordering convenient to currying
Keep rightmost the data to be operated
17. Globalcode – Open4education
Turn a function that expects
multiple arguments into one that,
when supplied fewer arguments,
returns a new function that awaits
the remaining ones
18. Globalcode – Open4education
Ramda is about currying
const cookPasta = R.curry((water, heat, pasta) => { ... })
// Have everything needed
cookPasta (water, heat, pasta)
// Forgot to buy pasta
cookPasta (water, heat)(pasta)
// No gas and no pasta
cookPasta (water)(heat, pasta)
// Had to go twice to supermarket
cookPasta (water)(heat)(pasta)
35. Globalcode – Open4education
Function functions
// Always return the same thing, ignoring arguments
const name = R.always('Derek')
name('Willian') //=> Derek
// Functional if then else, a.k.a. Maybe Monad
const findName = R.ifElse(
R.has('name'),
R.prop('name'),
R.always('No name')
)
findName({ title: 'Mr.', name: 'Derek' }) //=> Derek
findName({ title: 'Mr.' }) //=> No name
// Pipe functions left-to-right. First function can have any arity
// Others must have arity of exactly one
const calculate = R.pipe(Math.pow, R.negate, R.inc);
calculate(3, 2); // -(3^2) + 1
36. Globalcode – Open4education
Math functions
// Addition
R.add(1, 2) //=> 3
// Subtraction
R.subtract(2, 1) //=> 1
// Sum all elements
R.sum([1, 1, 1]) //=> 3
// Increment
R.inc(41) //=> 42
// Decrement
R.dec(43) //=> 42
// Calculate the mean
R.mean([2, 7, 9]) //=> 6
37. Globalcode – Open4education
List functions
// Check if all elements match a predicate
R.all(R.gt(4), [1, 2, 3]) //=> true
// Check if a number is inside a list
R.contains(3, [1, 2, 3])
// Drop elements from start
R.drop(1, ['foo', 'bar', 'baz']) //=> ['bar', 'baz']
// Find elements using a predicate
const list = [{a: 1}, {a: 2}, {a: 3}]
R.find(R.propEq('a', 2))(list) //=> {a: 2}
R.find(R.propEq('a', 4))(list) //=> undefined
// Flatten a list of list into a single list
const list = [1, 2, [3, 4], 5, [6, [7, 8, [9, [10, 11], 12]]]]
R.flatten(list) //=> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
38. Globalcode – Open4education
Logic functions
// Combine predicates into a single function
var gt10 = x => x > 10
var even = x => x % 2 === 0
var gt10even = R.both(gt10, even)
gt10even(100) //=> true
gt10even(101) //=> false
// Functional switch case (aka. pattern matching?)
var whatHappensAtTemperature = R.cond([
[R.equals(0), R.always('water freezes at 0°C')],
[R.equals(100), R.always('water boils at 100°C')],
[R.T, temp => 'nothing special happens at ' + temp + '°C']
])
whatHappensAtTemperature(0) //=> 'water freezes at 0°C'
whatHappensAtTemperature(50) //=> 'nothing special happens at 50°C'
whatHappensAtTemperature(100) //=> 'water boils at 100°C'
39. Globalcode – Open4education
Object functions
// Add a key and value to an already existing object
R.assoc('c', 3, {a: 1, b: 2}) //=> {a: 1, b: 2, c: 3}
// Remove a key from an already existing object
R.dissoc('b', {a: 1, b: 2, c: 3}) //=> {a: 1, c: 3}
// Do the same with a nested path
R.assocPath(['a', 'b', 'c'], 42, {a: {b: {c: 0}}})
//=> {a: {b: {c: 42}}}
// Check if an object contains a key
var hasName = R.has('name')
hasName({name: 'alice'}) //=> true
hasName({name: 'bob'}) //=> true
hasName({}) //=> false
// Pick some properties from objects
var abby = {name: 'Abby', age: 7, hair: 'blond', grade: 2}
var fred = {name: 'Fred', age: 12, hair: 'brown', grade: 7}
R.project(['name', 'grade'], [abby, fred])
//=> [{name: 'Abby', grade: 2}, {name: 'Fred', grade: 7}]