Pure function - a function that has no side effects. When called it should return a value without changing the state of the system
Side effect - A change that occurred indirectly when a function was called
Making things pure makes programs easier to write and read. It makes things more reasonable and less complex
A pure function can access state as long as it doesn’t change it
Example of impure function
function foo(x){
y = y * x;
z = z * x;
}
let y = 2, z = 3;
foo(5);
Example of pure function
function bar(x, y, z){
foo(x);
return [y,z];
function foo(x){
y = y * x;
z = z * x;
}
}
bar(5, 2, 3);
The output of one function is the input of another function
In this example the side effect doesn’t cause different values to return but there’s still a side effect by changing the value of z
function sum(x, y){
return x + y;
}
function mult(x, y){
return x * y;
}
let z = mult(3, 5);
z = sum(z, 2);
It would be better written using composition in a utility function like so:
function multAndSum(x, y, z){
return sum(mult(x, y), z);
}
multAndSum(3, 5, 2);
non mutation - the non ability to change value
var x = 2;
x++; // allowed
const y =3;
y++; // not allowed
const z = [4,5,6];
z = 10; // not allowed
z[0] = 10; // allowed
const w = Object.freeze([4,5,6]);
w = 10; // not allowed
w[0] = 10; // not allowed
Object.freeze only affects the top level
Very easy to change values as each variable is just a reference to an object
If two variables reference the same object then it’s possible to change both when not intended
let myArr = [1,2,3]
let myArr2 = myArr
myArr2[0] = 4
console.log(myArr[0]) // 4
Immutability is a discipline, given values we choose not to change them
Whether the value is changeable is not really the point
Instead of making a reference to an array and changing it or one of it’s values, we should make a new copy of it and work with that. I will not mutate it.
In a functional programming language you cannot mutate state
In JavaScript we can choose not to mutate state instead
function doubleThemMutable(list) {
for(var i=0; i<list.length; i++){
list[i] = list[i] * 2;
}
}
function doubleThemImmutable(list) {
var newList = []
for(var i=0; i<list.length; i++){
newList[i] = list[i] * 2;
}
return newList;
}
Simple primitives are passed as new copies Non-simple primitives are passed as references
Closure is when a function ‘remembers’ the variables around it when that function is executed elsewhere
A non functional example of closure
function foo() {
var count = 0;
return function() {
return count++;
}
}
const x = foo();
x(); // 1
x(); // 2
x(); // 3
State is being modified here so it isn’t pure
Useful example of closure / currying
function foo(x, y) {
return function(){
return x + y;
}
}
var x = foo(3, 4);
x(); // 7
x() will return 7 every time
3 and 4 are stored in the closure
A function you define that’s going to perform an action and call itself until it reaches a base case
• Has a base case • Calls itself using it’s own name to call
More than one function calling each other until they reach a base case
There are physical limitations on how many executing functions that can be stored in memory
A stack frame is stored in memory when a function is called, IE used to have a limit of 13 functions that could be calling each other at once
These days the limit is much larger but still a concern
There is a performance optimisation in ES6, if you use a proper tail call then the recursion will only use one stack frame no matter how deep
function sumIter(){
var sum = 0;
for(var i=0; i<arguments.length; i++){
sum = sum + arguments[i];
}
return sum;
}
console.log(sumIter(3,4,5)); // 12
Recursive solution
function sumRecursive(...args) {
if(args.length <= 2){
return args[0] + args[1];
}
return(
args[0] +
sumRecursive(...args.slice(1))
)
}
console.log(sumRecursive(3,4,5)); // 12
The slice array method is good for immutability as it returns a new array rather than modifying the one it is run on
A transformation is taking a value and doing something to it so you get a different value
The map operation runs a function against every item in a list and returns a new list that is the same length with the new values calculated by the function
Map is useful in functional programming as it returns a new array so is good for maintaining immutability
Map is a prototypal method of the Array object which makes it harder to compose, composition is done through chaining calls together
It is however really easy to use
The predicate is the transformer function you pass in
If we wanted to run two map functions we want to run on an array it is preferable to combine the functions into one and only do one map operation. We shouldn’t be chaining multiple map and filter calls ideally
function doubleIt(v) {
return v * 2;
}
console.log([1,2,3,4,5].map(doubleIt));
You can filter an array using a predicate function, the value returned determines if the array items are included in the new array or not
If you want to include / exclude based on something more complicated than just the value then you shouldn’t use filter
Filter is an immutably principled operation, it returns a new array
The new list has potentially fewer items, maybe none
If the predicate returns a true value for a value it is included in the new array, otherwise it isn’t
function isOdd(v){
return v % 2 == 1;
}
console.log([1,2,3,4,5].filter(isOdd));
An example of a reduction would be to get the summation of every item in a list
The reduce operation is more complex than the previous two
It is easy to not use this functionally
The parameters passed to the predicate are called the the accumulator and the value
An initial value is passed in the the reduce predicate, for multiplication this should be 1, for summation this should be 0
Reduce returns a result that isn’t necessarily an array but could be
A partial reduction returns another list
function mult(x, y){
return x * y;
}
[1,2,3,4,5].reduce(mult, 1)
The only way that forEach is useful is if the predicate has a side effect
For this reason it is not pure
Most functional programmers will tell you never to use forEach, it’s all about side effects
Wrapping values in functions It can be useful sometimes to wrap values in functions
e.g.
function foo(){
return 42;
}
A function wrapped around a value is called a thunk
Will provide map and reduce but not filter, you can make filter easily using map and reduce
Predicate Monad Writing recursive functions Y combinator, alternative to recursion Ramda, baconJs