2. What is FP?
“Functional programming refers to the
declarative evaluation of pure functions to
create immutable programs by avoiding
externally observable side effects.”
3. Why?
• Reduce complexity
• Create code that is easier to trace, debug, and
test
• Modularize code leads to separation of concerns
• Avoid duplications
• Implement changes unobtrusively
• Create code that is extensible and configurable
• Foundation for Rx and reactive programming
4. Why Learn it now?
• Most newer languages are/have incorporated
functional features into them.
– Java (streams, function interfaces, lambda
expressions)
– Scala (hybrid FP + OO)
– F# (immutable structures, pipes)
• LINQ
– ES6 JavaScript -> ES7 JavaScript will have streams
– Clojure, Lisp, Scheme, Haskell, OCaml, Erlang, etc
• We live in a highly concurrent world
5. Paradigm shift
• Eliminate externally observable side effects
• Control (reduce or eliminate) mutations
• Write declaratively and point-free
• Everything is a value (even functions)
• Functions ALWAYS return values
• Recursion as looping mechanism (eliminate
loops)
5
6. The OO World
6
Data and behavior tightly
coupled
ClassA
data
behavior
ClassB
data
behavior
ClassC
data
behavior Unit testing is challenging
Unit of work: Classes
7. function doWork(objectA): objectB
The FP World
function doMoreWork(objectB): objectC
function displayResults(objectC)
Data and behavior loosely
coupled
Unit testing is (basically)
free
Unit of work: Function
8. Is JavaScript functional?
JavaScript is a dynamic, object-oriented programing
language whose expressive power via closures and
high-order functions makes it compelling for writing in
a functional style.
Features that favor functional programming:
• const keyword
• Promises
• Lambda expressions + closures
• Generators and Iterators
• FP libraries (Ramda.js, Underscore.js, Lodash.js, etc)
11. Even more functional Hello World!
compose (
addToDom('#msg'),
h2,
repeat(3),
escapeChars)('Hello World');
Extensible
12. Declarative Programming
• Describe WHAT a program does
• Not HOW to do it
SQL>
SELECT firstname, birthYear FROM Person
WHERE year > 1903 AND country = 'US'
GROUP BY firstname, birthYear
FP>
compose(select(firstname, birthYear),
from('Person'),
where(year => year === 1903),
where(country => country === 'US'),
groupBy(firstname, birthYear))(query);
13. First let’s look at the current
state of things
Imperative Programming
14. function addToTable(personId) {
if(personId != null) {
personId = studentId.replace(/^s*|-|s*$/g, '');
if(personId.length !== 9) {
throw new Error('Invalid Input');
}
var person = db.get(personId);
if (person) {
var rowInfo =
`<td>${person.ssn}</td>
<td>${person.firstname}</td>
<td>${person.lastname}</td>`;
$(`#${tableId}
tr:last`).after(`<tr>${rowInfo}</tr>`);
return $(`#${tableId} tr`).length - 1;
}
else {
throw new Error('Person Record not found!');
}
}
else {
return 0;
}
}
17. First, you need to understand…
• The issue with side effects and mutations
• Singularity principle
• Currying and composition
• Functors and Monads
21. Lenses: object mutations
const person = new Person('Alonzo', 'Church');
const lastnameLens = lenseProp('lastName');
view(lastnameLens, person); //-> 'Church'
const newPerson = set(lastnameLens,
'Mourning', person);
newPerson.lastname; //-> 'Mourning’
person.lastname; //-> 'Church'
var person = {
firstname:'Alonzo’,
lastname: 'Church'
}
22. Singular Functions
• Singularity principle: functions are supposed
to perform only one task
• Simple functions typically have fewer
arguments (reduced arity) than complex
functions
• Simple functions are easy to test, but also
composeable and chainable
23. Currying
• Some functions can’t be reduced to single arguments
• Used to partially evaluate a function as a sequence of
steps by providing arguments one-at-a-time
• Currying enables the composition of complex
functions
function f(a, b, c) { … }
f a f(a, undefined, undefined)
evaluating: returns:
( )
24. function f(a, b, c) { … }
f(a, b, c) {
return function (a) {
return function (b) {
return function (c) {
…
}
}
}
}
Currying2
25. f a f(b, c)
Evaluating:
f a f(c)b
f a resultb c
returns:
(
(
(
)
)
)
Currying3
26. Currying Example
var name = curry2(function (first, last) {
return [last, first].join(',');
});
name('Haskell'); //-> Function
name('Haskell')('Curry'); //-> 'Curry, Haskell'
27. Composition
• Loosely couple a function’s return value
with another function’s arguments
(pipeline)
• Separates a program’s description from
evaluation
• The resulf of composing a function is
another function that can be composed
further
29. Composition example
var str = `A complex system that works is invariably
found to have evolved from a simple system that
worked`;
var explode = str => str.split(/s+/);
var count = arr => arr.length;
var countWords = compose(count, explode);
countWords(str); // -> 17
37. Containerizing
37
const Wrapper = function (val) {
this._val = val;
};
// Map
Wrapper.prototype.map = function (f) {
return f(this._val);
};
// Unit
const wrap = (val) => new Wrapper(val);
guarded
identity
map
identity returns
the same value
Wrapper
38. Containerizing2
const wrappedValue = wrap('Get Functional');
// extract the value
const value =
wrappedValue.map(toUpper).map(repeat(2)).map(identity);
value; //-> 'GET FUNCTIONAL GET FUNCTIONAL'
39. • Data structure that can be mapped over
• Lift values into a container so that you can apply
functions onto them, place the result back into the
container
Functors: next level containers
39
// Functor
Wrapper.prototype.fmap = function (f) {
return wrap(f(this._val));
};
40. Functors2
40
const plus = curry((a, b) => a + b);
conts plus3 = plus(3);
const two = wrap(2);
const five = two.fmap(plus3); //-> Wrapper(5)
two.fmap(plus3).fmap(plus10); //-> Wrapper(15)
plus3
fmap
Wrapper
2
Wrapper
2
apply function
Wrapper
5
wrap
41. What can we do with containers?
41
Wrap a potentially null value or
a function that can cause the
program to fail
45. Monads2
45
• Backbone of functional
programming
• Treat data and operations
algebraically
• Data type used for applying a
sequence of transformations on
data (conveyor belt model)
• Abstract data flows
• Used for error handling, IO,
Logging, etc
46. So call me: Maybe
46
• Wall-off impurity
• Consolidate null-check logic
• Consolidated exception throwing
• Support compositionally of functions
• Centralize logic for providing default values
48. Maybe: Just
48
class Maybe {
static fromNullable(a) {
return a !== null ?
just(a) : nothing();
}
static of(a) {
return just(a);
}
}
class Just extends Maybe {
map(f) {
return
of(f(this.value));
}
getOrElse() {
return this.value;
}
}
49. Maybe: Nothing
49
class Nothing extends Maybe {
map(f) {
return this; // noop
}
get value() {
throw new TypeError(`Can't extract
the value of a Nothing.`);
}
getOrElse(other) {
return other;
}
}
51. Remove nested code
51
function getCountry(student) {
var school = student.school();
if (school !== null ) {
var addr = school.address();
if (addr !== null ) {
return addr.country();
}
}
return 'Country does not exist!';
}
student; //-> Maybe<Student>
const getCountry = student => student
.map(prop('school'))
.map(prop('address'))
.map(prop('country'))
.getOrElse('Country does not
exist!');
52. Monads abstract data flow
+ Error Handling
52
trimxxx-xxx id normalize id findPerson
addToTable(personId)
nullpopulateRow
Left
null
Left
appendToTable
orElse console.log
skipped skipped
props
skipped
When an error occurs, Maybe safely propagates
the error through the components of your code
56. Thinking this way will…
• Allow you create modular, testable, reliable,
and robust applications
• Decompose, decompose, decompose!
• Pure functions: help design for concurrency
• Enable other paradigms:
– Reactive programming
– Concurrent programming
– Immutable architectures?
Changing a variable, property or data structure globally
Changing the original value of a function’s argument
Processing user input
Throwing an exception, unless it’s caught within the same function
Printing to the screen or logging
Querying the DOM or databases
John Gall : The Systems Bible
Handle with the same elegance? Error handling tends to be very messy with try/catch statements
Chain -> also known as flatMap
Handle with the same elegance? Error handling tends to be very messy with try/catch statements