Functional programming in JavaScript Part 2 – Combinators
Pawel Ged
Vue.js Developer
This is a second part of our series of articles devoted to power of functional programming in JavaScript. Check this article to expand your knowledge on Combinators.
Introduction to Combinators
Combinators are higher-level function that allows you to combine functions, variables, or other combinators. Usually, they do not contain declarations of their own variables or business logic. They are the only ones to flush the control in a function program.
In this article, I will try to cover a few of them:
Tap
Currying
Pipe/Compose
Fork
Alternation
Sequence
Tap
A combinator is very useful for functions that return nothing. It takes the function to which the parameter goes and then it is returned.
const [items, setItems] = useState(() => [])
axios
.get('http://localhost')
.then({ data } => {
setItems(data)
console.log(data)
onLoadData(data)
}).then(...) // returns undefined - the data in the promise has been modified
Declarative example
const [items, setItems] = useState(() => [])
axios
.get('http://localhost')
.then(({ data }) => data)
.then(tap(setItems)) // (data) => { setItems(data); return data }
.then(tap(console.log)) // one then = one function = one responsibility
.then(tap(onLoadData))
.then(...) // still access to original data
// easy on maintain open/close principle
Currying
It splits the arguments of a function and makes it possible to call them sequentially.
const sum = (a, b, c) => a + b + c
const currySum = curry(sum)
/*
possible calls
currySum(a)(b)(c),
currySum(a)(b,c),
currySum(a,b)(c),
currySum(a,b,c)
*/
currySum(1) // (b, c) => 1 + a + b or (b) => (c) => 1 + a + b
currySum(5)(10) // (c) => 5 + 10 + b
currySum(5, 10) // (c) => 5 + 10 + b
currySum(5)(10)(20) // 35
currySum(5, 10)(20) // 35
currySum(5)(10, 20) // 35
const divideBy = curry((a, b) => b / a)
const multiplyBy = curry((a, b) => a * b)
const divideByTwo = divideBy(2)
divideByTwo(10) // returns 5
const multiplyByFive = multiplyBy(5)
multiplyByFive(10) // returns 50
Pipe/Compose
Through composition, it is possible to pass data from one function to another. It is important that the functions take the same number of arguments. The difference between pipe and compose is that the first one executes the function from first to the last, and compose calls them from the end.