Point-free style is a really cool mechanic that can help establish good practices in regards to functional programming.
const arr = [1,2,3]
arr.forEach(console.log)
Output:
1 0 [ 1, 2, 3 ]
2 1 [ 1, 2, 3 ]
3 2 [ 1, 2, 3 ]
What's going on here?
Normally, we would see forEach
used with a callback.
arr.forEach((curr, idx, arr) => console.log(curr, idx, arr))
Output:
1 0 [ 1, 2, 3 ]
2 1 [ 1, 2, 3 ]
3 2 [ 1, 2, 3 ]
With point-free style, we implicitly pipe the incoming arguments into the callback function.
(curr, idx, arr) => console.log(curr, idx, arr)
// we can simplify and imply that the arguments will go into the callback function, and it will just work
console.log
This will work with any callback function wherein the parent function needs to pass in values to the callback. The pattern is especially useful with iterables.
const strArr = ['FOO', 'BAR', 'BAZ']
function getLowerCase(val) { return val.toLowerCase() }
// point-free version of strArr.map(item => getLowerCase(item))
const lower = strArr.map(getLowerCase)
console.log(lower)
// [ 'foo', 'bar', 'baz' ]
Here's another example using Array.prototype.every
.
function isOddValue(value) { return value % 2 === 1 }
const arr = [1,3,5]
console.log(
// point-free version of arr.every(item => isOddValue(item))
arr.every(isOddValue)
)
// true
This snippet of code has two examples of point-free style.
function resolver(cb) { cb(1) }
const p = new Promise(resolver)
p.then(console.log)
Output:
1
In this example, we're passing the promise's first argument (the resolving function) into resolver
. resolver
then calls this function. This causes the promise's then
branch to be entered since the promise resolved.
We use point-free style again to implicitly pipe the resolved value into the console.log()
, resulting in the value 1
being printed.
Any time you see a callback function, there is probably a simplified point-free solution that can be implemented.
map(value => cb(value))
/* equivalent to */
map(cb)