8. Javascript - important features for FP
HAS
Anonymous functions and concise
lambda syntax
Closures
Higher-order functions
First class functions
DOES NOT HAVE
Purity
Immutability
Recursion
9. Concise lambda syntax
lambda expressions are abstractions which enable a function to be passed around like
data (value)
ES6 fat arrow
(x, y) => x * y
10. Closures
A closure is the combination of a function bundled together (enclosed) with
references to its surrounding state (the lexical environment).
14. First Class Functions - use their power
layers of indirection with no added value
const fullname = user => `${user.firstName} ${user.lastName}`
const fullnames = users.map(user => fullname(user))
const fullnames = users.map(fullname)
18. First Class Functions - help with
layers of indirection with no added value
> amount of redundant code to maintain and search through
name and reference arguments
19. First Class Functions - Naming
// specific to our current blog
const validArticles = articles =>
articles.filter(article => article !== null && article !== undefined)
// vastly more relevant for future projects
const compact = xs => xs.filter(x => x !== null && x !== undefined)
20. Pure Functions
A pure function is a function where the return value is only determined by its input
values, without observable side effects.
21. Pure Functions - Example
let G = 6.67408
const force = (m1, m2, r) => G * m1 * m2 / (r * r)
22. Pure Functions - Example
let G = 6.67408
const force = (m1, m2, r) => G * m1 * m2 / (r * r)
❌
23. Pure Functions - Example
const trace = (title, text) => console.log(title, text)
24. Pure Functions - Example
const trace = (title, text) => console.log(title, text)
❌
25. Pure Functions - Example
const max = (m1, m2) => m1 > m2 ? m1 : m2
26. Pure Functions - Example
const max = (m1, m2) => m1 > m2 ? m1 : m2
✅
27. Pure Functions - Example
const oneDayLater = () => {
const today = moment();
return moment(today).add(1, 'days');
}
28. Pure Functions - Example
const oneDayLater = () => {
const today = moment();
return moment(today).add(1, 'days');
}
❌
31. Pure Functions - Example
const signUp = (attrs) => {
const user = saveUser(attrs);
welcomeUser(user);
};
32. Pure Functions - Example
const signUp = (attrs) => {
const user = saveUser(attrs);
welcomeUser(user);
};
❌
33. Pure Functions - Example
const signUp = (Db, Email, attrs) => {
const user = saveUser(Db, attrs);
welcomeUser(Email, user);
};
34. Pure Functions - Example
const signUp = (Db, Email, attrs) => {
const user = saveUser(Db, attrs);
welcomeUser(Email, user);
};
❌
35. Side Effects
changing the file system
inserting a record into a database
making an http call
mutations
printing to the screen / logging
obtaining user input
querying the DOM
accessing system state
36.
37. Pure Functions - Example
const signUp = (Db, Email, attrs) => () => {
const user = saveUser(Db, attrs);
welcomeUser(Email, user);
};
❌✅
44. Offer Referential Transparency
In functional programming, referential transparency is generally defined as the fact
that an expression, in a program, may be replaced by its value (or anything having the
same value) without changing the result of the program.
45. Easy to reason about
no need to search for context
everything depends just on the input arguments
50. Curry
A curried function is a function that takes multiple arguments one at a time.
Call this function with one argument and it returns a function that takes the
remaining arguments
const sum = (x, y) => x + y;
const sum = x => y => x + y;
const increment = sum(1)
const add10 = sum(10)
51. Curry base
const match = curry((what, s) => s.match(what));
const replace = curry((what, replacement, s) => s.replace(what, replacement));
const filter = curry((f, xs) => xs.filter(f));
const map = curry((f, xs) => xs.map(f));
match(/r/g, 'hello world'); // [ 'r' ]
const hasLetterR = match(/r/g); // x => x.match(/r/g)
hasLetterR('hello world'); // [ 'r' ]
hasLetterR('just j and s and t etc'); // null
filter(hasLetterR, ['rock and roll', 'smooth jazz']); // ['rock and roll']
const removeStringsWithoutRs = filter(hasLetterR); // xs => xs.filter(x => x.match(/r/g))
removeStringsWithoutRs(['rock and roll', 'smooth jazz', 'drum circle']); // ['rock and roll', 'drum
circle']
const noVowels = replace(/[aeiou]/ig); // (r,x) => x.replace(/[aeiou]/ig, r)
const censored = noVowels('*'); // x => x.replace(/[aeiou]/ig, '*')
censored('Chocolate Rain'); // 'Ch*c*l*t* R**n'
52. Curry - positioning of arguments
iteratee-first
data-last
preload data / dependencies
const findEven = numbers => filter(isEven, numbers)
// apply currying to get pointfree version
const findEven = filter(isEven)
https://hackernoon.com/javascript-and-functional-programming-pt-2-first-class-functions-4437a1aec217
https://medium.com/javascript-scene/why-learn-functional-programming-in-javascript-composing-software-ea13afc7a257
Purity: In JavaScript, purity must be achieved by convention. If you’re not building most of your application by composing pure functions, you’re not programming using the functional style. It’s unfortunately easy in JavaScript to get off track by accidentally creating and using impure functions.
Immutability: In pure functional languages, immutability is often enforced. JavaScript lacks efficient, immutable trie-based data structures used by most functional languages, but there are libraries that help, including Immutable.js and Mori. I’m hoping that future versions of the ECMAScript spec will embrace immutable data structures.
Recursion: JavaScript technically supports recursion, but most functional languages have a feature called tail call optimization. Tail call optimization is a feature which allows recursive functions to reuse stack frames for recursive calls.
Without tail call optimization, a call stack can grow without bounds and cause a stack overflow. JavaScript technically got a limited form of tail call optimization in the ES6 specification. Unfortunately, only one of the major browser engines implemented it, and the optimization was partially implemented and then subsequently removed from Babel (the most popular standard JavaScript compiler, used to compile ES6 to ES5 for use in older browsers).