Thinking in Expressions
What Are Expressions?
Imperative programs are built from statements, and read top to bottom.
let numbers = [1, 2, 3];
let sum = 0;
for (let i = 0; i < numbers.length; i++) {
sum += numbers[i];
}
Functional programs are composed of expressions, and read inside out.
Here’s the same program written in a functional style:
[1, 2, 3].reduce((a, b) => a + b, 0)
These expressions are atomic:
1
2
3
a
b
0
We compose bigger expressions from smaller ones:
1
2
3
->[1, 2, 3]
a
b
->a + b
Zoom out a little more:
[1, 2, 3]
->[1, 2, 3].reduce
a + b
->(a, b) => a + b
Zoom out all the way:
[1, 2, 3].reduce((a, b) => a + b, 0)
💡 In functional programming, every value is an expression, including the program itself.
Why Expressions?
Expressions are simpler to reason about
FP offers a simpler way of looking at the world:
- Every value is an expression
- Strings, numbers, and booleans are expressions
- Arrays and objects are expressions
- Functions are expressions
-
Any expression can be replaced with its simplest value without changing the program:
1 + 2
can be replaced by3
and vice versa5 * 3
can be replaced by15
and vice versaMath.sqrt(16)
can be replaced by4
and vice versa[1, 2, 3].reduce((a, b) => a + b, 0)
can be replaced by6
and vice versa
Expressions are simpler to refactor
- Find the expression you want
- Draw a box around it
- Move it around anywhere inside its parent “box”
For example, let’s extract [1, 2, 3]
into a variable:
let numbers = [1, 2, 3]
numbers.reduce((a, b) => a + b, 0)
Extract (a, b) => a + b
into a variable:
let numbers = [1, 2, 3]
let add = (a, b) => a + b
numbers.reduce(add, 0)
Wrap it into a reusable function:
let add = (a, b) => a + b
let sum = (numbers) => numbers.reduce(add, 0)
sum([1, 2, 3])
Summary
- Every value is an expression
- Expressions can be replaced by their simplest values
- Expressions are simpler to refactor and reason about