Table of Contents
- 1. Why?
- 2. Concepts
- 3. Further concepts
- 4. First-class functions
- 5. Higher-order functions
- 6. Higher-order functions (cont.)
- 7. Pure functions
- 8. Recursion
- 9. Partial application
- 10. Partial application (cont.)
- 11. Currying
- 12. Easy Currying
- 13. Practical Currying
- 14. Functional composition
- 15. Functional composition (cont.)
- 16. pipe
- 17. Point-free programming
- 18. Further Resources
1 Why?
Imperative programming is concerned with how
Functional programming is concerned with what
2 Concepts
- First-class Functions
- Higher-order Functions
- Recursion
- Pure functions
- Currying & Partial Application
3 Further concepts
- Lazy Evaluation
- Types & Data Structures
- Category Theory
4 First-class functions
- Are values
- Have no restriction on their use
- Enable the use of callback functions in JavaScript
var fn = function () {
return 2
}
5 Higher-order functions
Functions that operate on other functions are higher-order functions
var succ = function (x) {
return x + 1
}
var arr = [1, 2, 3, 4]
arr.map(succ)
Here, Array.prototype.map
is the higher-order function
6 Higher-order functions (cont.)
Functions that return functions are also higher-order functions
function adder (n) {
return function (x) {
return n + x
}
}
var add1 = adder(1)
adder
is a higher-order function
7 Pure functions
Functions without side-effects
var succ = (x) => x + 1
console.log(succ(succ(1)))
// could be optimised away by a compiler, e.g.:
console.log(3)
8 Recursion
Functions that call themselves
function fibonacci (n) {
switch (n) {
case 0:
case 1:
return 1
default:
return fibonacci(n - 1) + fibonacci(n - 2)
}
}
9 Partial application
The infamous Function.prototype.bind
in JavaScript
function add (x, y) {
return x + y
}
var add1 = add.bind(add, 1)
add1(3) // = 4
10 Partial application (cont.)
After ES6 introduced arrow functions, partial application has become more popular
var add = x => y => x + y
11 Currying
Related to partial application, but more implicit and general
Translates 1 function of arity n to n functions of arity 1
function volume (w, d, h) {
return w * d * h
}
var vol = curry(volume)
vol(10)(20)(30)
// is strictly equivalent to
volume(10, 20, 30)
12 Easy Currying
In order to make currying (and partial application) easier to use, move the most important argument to a function to the end:
var badMap = (arr, fn) => arr.map(fn)
var goodMap = (fn, arr) => arr.map(fn)
var curriedBadMap = curry(badmap)
var curriedGoodMap = curry(goodMap)
var goodDoubleArray = goodMap(x => x * 2)
var badDoubleArray = badMap(_, x => x * 2)
The bad version requires the curry function to support a magic placeholder argument and doesn't look as clean.
13 Practical Currying
Currying is not automatic in JavaScript, as in other languages
External tools aren't (so far) able to statically analyse curried functions
Solution: Don't expose curried functions Instead, write functions as if currying were automatic
If consumers want to curry, they can. If they don't, their editor or language server will show them the arguments
14 Functional composition
Creating functions from other functions
Usually provided by compose
(right-to-left) and pipe
(left-to-right)
A very simple definition of compose
for only two functions would look like this
function compose (f, g) {
return function (...args) {
return f(g(...args))
}
}
15 Functional composition (cont.)
var plusOne = x => x + 1
var timesTwo = x => x * 2
var plusOneTimesTwo = compose(timesTwo, plusOne)
var timesTwoPlusOne = compose(plusOne, timesTwo)
nextDoubled(3) // = (3 + 1) * 2 = 8
doubledPlusOne(3) // = (3 * 2) + 1 = 7
16 pipe
What about pipe
?
pipe
does the same thing, but runs the functions the other way around
pipe(f, g)
is the same as compose(g, f)
17 Point-free programming
With currying and higher-order functions, we (often) don't need to declare function arguments
var modulo = a => b => b % a
var eq = a => b => a === b
var isEven = x => eq(0)(modulo(2)(x))
var isEvenPointFree = compose(eq(0), modulo(2))
18 Further Resources
- Mostly adequate guide to FP (in javascript)
- Ramda, a general-purpose FP library
- Sanctuary, a JavaScript library for Haskellers