4. What we want?
● Describe what to do instead of how
● Avoid duplication
● Stop reinventing common functionality
● Composition
● Less code - less bugs))
6. Accept functions as arguments
[1, 2, 3].map(function (x) {
return -x
})
Return function as result
function fn (a, b) {
return a + b
}.bind(undefined, 1, 2) // => fn(1, 2)
Higher order functions
7. Currying
var add = R.curry(function (x, y) {
return x + y
})
add(4, 2) // 6
add(4)(2) // 6
var add4 = add(4) // fn !
add4(2) // 6
add() // fn !
8. Function first, data last
var data = [ {id: 1, price: “33.00”, amount: 798},
{id: 5, price: “22.00”, amount: 0}, … ]
// Our task is to get all sold products
var getProducts = R.filter(
R.propEq(“amount”, 0)
) // (list) => list.filter( (item) => item.amount === 0 )
getProducts(data) // [{id: 5, price: “22.00”, amount: 0}, ...]
9. Dictionary for the next slide
R.pipe - Performs left-to-right function composition. The leftmost function may
have any arity; the remaining functions must be unary.
R.prop - Returns a function that when supplied an object returns the indicated
property of that object, if it exists.
R.__ - A special placeholder value used to specify "gaps" within curried functions,
allowing partial application of any combination of arguments, regardless of their
positions.
R.gt - (a, b) => a > b
10. Functions composition e.g.: pipe, compose...
var data = [ {id: 1, price: “150.00”, amount: 798},
{id: 5, price: “22.00”, amount: 0}, … ]
// Now task is to get “id” and “price” of all available and
expansive products
var available = R.pipe(R.prop(“amount”), R.gt(R.__, 0))
// (item) => item.amount > 0
var expansive = R.pipe(R.prop(“price”), parseFloat, R.gt(R.__, 100))
// (item) => parseFloat(item.price) > 100
...
11. Functions composition II
var data = [ {id: 1, price: “150.00”, amount: 798},
{id: 5, price: “22.00”, amount: 0}, … ]
...
var filterProducts = R.filter(
R.allPass([available, expansive]))
var getProducts = R.pipe( filterProducts, R.pick([“id”, “price”]) )
getProducts(data) // [{id: 1, price: “150.00”, amount: 798}, ...]
12. Point free - function evolution
Past (dark ages)
function makeMeHappy() {
b = a + 42 // a and b are somewhere in the scope
}
Present (renaissance)
const makeMeHappy = a => a + 42
Future (post-postmodernism but nobody knows, really...)
const makeMeHappy = R.add(42)
13. Dictionary for next slide
R.converge - Boring long definition…
R.find - Returns the first element of the list which matches the predicate
R.nthArg - Returns a function which returns its nth argument
14. Point free II “overrefactoring”
var numberPropGt = R.curryN(3, R.
converge(
R.gt,
[ R.pipe(
R.converge(R.prop,
[R.nthArg(0),
R.nthArg(2) ]),
parseFloat ),
R.nthArg(1)
]
))
var available = numberPropGt(“amount”, 0)
// (item) => parseFloat(item.amount) > 0
var expansive = numberPropGt(“price”, 100)
// (item) => parseFloat(item.price) > 100
...
15.
16. Point free III real example
// findById :: String -> Array -> Object
const findById = R.converge(
R.find,
[
R.pipe(R.nthArg(0), R.propEq("id")),
R.nthArg(1)
]
)