Summary
HOFs
js
// Accepts function as an argument
function apply(f) {
return f(1);
}
apply(x => x + 1); // -> 2
// Returns a function
function applied(x) {
return () => x + 1;
}
applied(1)(); // -> 2
Lambda functions
js
// Unary lambda functions
const identity = x => x;
identity(1); // -> 1
const increment = x => x + 1;
increment(1); // -> 2
// Binary lambda functions
const add = (x, y) => x + y;
add(1, 2); // -> 3
// Nullary lambda functions
const one = () => 1;
one(); // -> 1
Concept
Higher order functions, either:
- accepts a function as an argument
- returns a function
The idea of functions as variables
Scopes
- look for the closest surrounding name declaration
- if not declared within current scope/block, look one level up
Lambda function is declared, but never initialised until function application
js
const f = x => y; // 1. Declaration of lambda function f, read rest of program // 6. f called wth arg 2, y was initialiesd as 1, return 1
const y = 1; // 2. Declaration of y, y initialised as 1, read rest
const g = y => f(y); // 3. Declaration of lambda function g, read rest // 5. g called with arg 2, apply f with arg 2 // 7. f returned 1, return 1
g(2) // 4. Apply g with arg 2 // 8. return 1
Application
Nesting vs Chaining
js
const twice = f => x => f(f(x));
const thrice = f => x => f(f(f(x)));
// let f be an arbitrary unary function
// let x be an arbitrary variable that f accepts
// Nesting
thrice(twice(f))(x);
// -> thrice(f(f(x)))(x);
// -> (f(f( f(f( f(f(x)) )) )))(x);
// -> f(f( f(f( f(f(x)) )) )); f is applied 6 times
js
// Chaining
thrice(twice)(f)(x);
// -> (twice(twice(twice(f))))(x);
// -> (twice(twice( f(f(x)) )))(x);
// -> (twice( f(f( f(f(x)) )) ))(x);
// -> ( f(f( f(f( f(f( f(f(x)) )) )) )) )(x); f is applied 8 times
Function currying
js
const add = (x, Y) => x+y;
add(1, 2); // -> 3
const curried_add = x => y => x + y;
curried_add(1)(2); // -> 3