First, Some Caveats
1. I do not do 100% functional programming
2. I will be showing examples in Javascript
3. I do not currently use functional reactive programming
Slide 3
Slide 3 text
What is Functional Programming?
1. Imperative vs. Declarative
2. Persistent and Immutable Data
3. No Side Effects
4. Noun vs. Verb
5. First class and higher order functions
6. Recursive over iterative
Slide 4
Slide 4 text
Common Functions
1. Map (transform to some)
2. Filter
3. Reduce
Slide 5
Slide 5 text
Recursive vs. Iterative
Slide 6
Slide 6 text
Iterative Factorial
var num = 5,
total = 1;
if (num !== 0) {
for (i = 1; i <= num; i++) {
console.log(i);
total = total * i;
}
}
console.log(total);
Slide 7
Slide 7 text
Recursive Factorial
var num = 5;
function factorial(n) {
if (n === 0) return 1;
return n * factorial(n - 1);
}
console.log(factorial(num));
Slide 8
Slide 8 text
Imperative vs.
Declarative
Imperative you express how to
do it, declarative you express
what you want done
Slide 9
Slide 9 text
Imperative
var list = [1, 2, 3, 4, 5],
total = 0;
for (i = 0; i < list.length; i++) {
total += list[i];
}
Slide 10
Slide 10 text
Declarative (Part 1)
var list = [1, 2, 3, 4, 5];
var total = list.reduce(function(result, num) {
return result + num;
});
Slide 11
Slide 11 text
Declarative (Part 2)
var list = [1, 2, 3, 4, 5];
function add(a, b) {
return a + b;
}
var total = list.reduce(add);
Slide 12
Slide 12 text
Declarative (Part 3)
var list = [1, 2, 3, 4, 5];
function add(a, b) {
return a + b;
}
function sum(items) {
return items.reduce(add);
}
var total = sum(list);
Slide 13
Slide 13 text
Using a Functional Language
Clojure
(def items `(1 2 3 4 5))
(reduce + items)
Requirements
1. Get a list of the average points for each player
2. Get an average for all players who have played 30 or more
games
Slide 17
Slide 17 text
Imperative
var playerAverages = [],
allPoints = 0,
allGames = 0;
for (i = 0; i < players.length; i++) {
var average = players[i].totalPoints / players[i].games;
playerAverages.push(average);
if (players[i].games >= 30) {
allPoints += players[i].totalPoints;
allGames += players[i].games;
}
}
var totalAverage = allPoints / allGames;
Slide 18
Slide 18 text
Declarative (Part 1)
var playerAverages = players.map(function(player) {
return player.totalPoints / player.games;
});
var players30Games = players.filter(function(player) {
return player.games >= 30
});
var points = players30Games.map(function(player) {
return player.totalPoints;
});
var games = players30Games.map(function(player) {
return player.games;
});
var totalPoints = sum(points),
totalGames = sum(games);
totalAverage = totalPoints / totalGames;
Slide 19
Slide 19 text
Declarative (Part 2)
function pluck(items, prop) {
return items.map(function(item) {
return item[prop];
});
}
function average(a, b) {
return a / b;
}
var playerAverages = players.map(function(player) {
return player.totalPoints / player.games;
});
var players30Games = players.filter(function(player) {
return player.games >= 30
});
var totalPoints = sum(pluck(players30Games, 'totalPoints')),
totalGames = sum(pluck(players30Games, 'games'));
totalAverage = average(totalPoints, totalGames);
Slide 20
Slide 20 text
Currying
Currying is the technique of translating the evaluation of a
function that takes multiple arguments (or a tuple of arguments)
into evaluating a sequence of functions, each with a single
argument (partial application).
–Wikipedia
Slide 21
Slide 21 text
Currying
function add(a) {
return function(b) {
return a + b;
}
}
var add10 = add(10);
console.log(add10(5)); // 15
Slide 22
Slide 22 text
Currying (Better Example)
var fullName = _.curry(function(first, middle, last) {
return [first, middle, last].join(' ');
});
var johnA = fullName('John', 'A.');
var johnASmith = johnA('Smith'); // John A. Smith
Slide 23
Slide 23 text
Currying (From Player Data
Example)
// Uses a library called Ramda
var players30Games = R.filter(R.pipe(R.get('games'),
R.lte(30)));
var totalPoints = R.pipe(players30Games,
R.pluck('totalPoints'),
R.sum);
totalPoints(players)
Slide 24
Slide 24 text
How is declarative helpful?
1. Testable, maintainable, evolvable code
2. Writing code at a higher level of abstraction
3. Through composition, it can lead to a very powerful way of
thinking (like SQL)
Slide 25
Slide 25 text
Persistent
Slide 26
Slide 26 text
Persistent State
1. Values are immutable
2. A "change" in a value returns a new value (old is never
thrown away)
3. These values persist (not necessarily on disk, but throughout
time)
4. Big plus: fast!
Slide 27
Slide 27 text
Crude Example
A -> B -> C
Sharing all of A
Z -> A -> B -> C
Sharing tail of A
Y -> B -> C
Slide 28
Slide 28 text
Persistence
1. Shared memory usage
2. No need to do deep clones of objects to avoid changing
state
3. Allows for immutable data
4. Allows for understanding what has changed
5. Allows for no side effects
Slide 29
Slide 29 text
Side Effects
Slide 30
Slide 30 text
Side Effects
var x = 10;
function a() {
x = 4;
}
console.log(x);
Slide 31
Slide 31 text
Side Effects
var x = 10;
function a() {
x = 4;
}
a();
console.log(x);
Slide 32
Slide 32 text
Mutable Data
Slide 33
Slide 33 text
Mutating Data
x = 4;
// ...later
x = 10;
y = x + 10;
Slide 34
Slide 34 text
Mutating Data
x = x + 1;
Slide 35
Slide 35 text
Why is persistence and
immutability good?
1. We've probably all spent hours chasing down bugs from
side effects
2. Code that mutates data requires following steps through
code to understand what it is doing
3. Mutating lots of code can be expensive
Slide 36
Slide 36 text
Libraries for Javascript
1. Underscore.js and Lo-Dash.js provide some functions
2. Ramda - Function-first library
3. Mori - Immutable data structures in Javascript
4. React.js and Immutable.js
5. ClojureScript
Slide 37
Slide 37 text
Recap, why is this helpful?
1. Code is more declarative
2. Promotes reusability and evolvability
3. Easier to write automated tests
4. Fewer bugs
Slide 38
Slide 38 text
Bonus
Functional Reactive Programming
Slide 39
Slide 39 text
FRP
There is no simple definition of this on the internet, so here are
some qualities.
1. Deal with events in a functional way
2. Create streams of events rather than event listeners
3. Free of side effects
Slide 40
Slide 40 text
Some Libraries
1. Bacon.js
2. Elm
3. RxJS
Slide 41
Slide 41 text
Bacon.js
function movieSearch(query) {
if (query.length < 3)
// show no results for queries of length < 3
return Bacon.once([]);
return Bacon.fromPromise(queryMovie(query));
}
var text = $('#input')
.asEventStream('keydown')
.debounce(300)
.map(function(event) {
return event.target.value;
})
.skipDuplicates();
// Only react to latest, in case they are out of order
var suggestions = text.flatMapLatest(movieSearch);
text.awaiting(suggestions).onValue(function(x) {
if (x) $('#results').html('Searching...');
});
suggestions.onValue(function(results) {
$('#results').html($.map(results, showMovie));
});