thinking functionally with javascript
TRANSCRIPT
![Page 1: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/1.jpg)
Thinking FunctionallyFunctional Programming using JavaScript
Luis Atencio@luijarBlog: http://luisatencio.net
![Page 2: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/2.jpg)
What is FP?
“Functional programming refers to the declarative evaluation of pure functions to
create immutable programs by avoiding externally observable side effects.”
![Page 3: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/3.jpg)
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
![Page 4: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/4.jpg)
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
![Page 5: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/5.jpg)
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)
![Page 6: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/6.jpg)
6
The OO World
Data and behavior tightly coupled
ClassA
data
behavior
ClassB
data
behavior
ClassC
data
behavior Unit testing is challenging
Unit of work: Classes
![Page 7: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/7.jpg)
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
![Page 8: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/8.jpg)
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)
![Page 9: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/9.jpg)
Hello World!
document.getElementById('msg').innerHTML = '<h1>Hello World</h1>';
compose(addToDom('#msg'), h1)('Hello World');
vs
![Page 10: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/10.jpg)
More functional Hello World!
compose ( addToDom('#msg'),
h2, repeat(3))('Hello World');
Declarative & configurable
![Page 11: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/11.jpg)
Even more functional Hello World!
compose ( addToDom('#msg'),
h2, repeat(3), escapeChars)('Hello World');
Extensible
![Page 12: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/12.jpg)
Declarative Programming• Describe WHAT a program does• Not HOW to do itSQL> 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);
![Page 13: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/13.jpg)
First let’s look at the current state of things
Imperative Programming
![Page 14: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/14.jpg)
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; }}
![Page 15: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/15.jpg)
… after thinking functionally……and some magic…
![Page 16: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/16.jpg)
16
var addToTable = compose( appendToTable(’personTable'),
populateRow, props(['ssn', 'firstname', lastname']),
findPerson, normalize, trim);
addToTable(personId);
![Page 17: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/17.jpg)
First, you need to understand…
• The issue with side effects and mutations• Singularity principle• Currying and composition• Functors and Monads
![Page 18: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/18.jpg)
Side effects
doWork doMoreWork
sharedData = [...]depends on updatechanges
coupling
1 2order matters
![Page 19: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/19.jpg)
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; }}
External Dependencies
Complexity
IO
![Page 20: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/20.jpg)
How do we deal with mutations?
![Page 21: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/21.jpg)
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'}
![Page 22: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/22.jpg)
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
![Page 23: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/23.jpg)
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:
( )
![Page 24: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/24.jpg)
function f(a, b, c) { … }
f(a, b, c) {
return function (a) { return function (b) {
return function (c) { …
} }
} }
Currying2
![Page 25: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/25.jpg)
f a f(b, c)
Evaluating:
f a f(c)b
f a resultb c
returns:
(((
))
)
Currying3
![Page 26: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/26.jpg)
Currying Example
var name = curry2(function (first, last) { return [last, first].join(',');}); name('Haskell'); //-> Function
name('Haskell')('Curry'); //-> 'Curry, Haskell'
![Page 27: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/27.jpg)
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
![Page 28: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/28.jpg)
Composition2
f•g(x) = f(g(x))
![Page 29: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/29.jpg)
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
![Page 30: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/30.jpg)
Composition is the backbone of modularity in FP
![Page 31: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/31.jpg)
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!'); } } ...
Breaking monolithic functions
![Page 32: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/32.jpg)
addToTable
cleanInputcheckLengthSsn
findPerson
populateRow
appendToTable
✔
✔
✔
Impure:can’t be tested
reliably
Decompose => Compose
Become the building blocks of your program
![Page 33: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/33.jpg)
Building blocks
const safeFindObject = curry(function (db, id) { return Maybe.fromNullable(db.get(id));});
const findPerson = safeFindObject(DB('people'));
const trim = (str) => str.replace(/^\s*|\s*$/g, '');
const normalize = (str) => str.replace(/\-/g, '');
![Page 34: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/34.jpg)
Building blocks2const populateRow = function (columns) { const cell_t = template('<td><%= a %></td>'); const row_t = template('<tr><%= a %></tr>'); const obj = function (a) { return {'a': a}; }; const row = compose( row_t, obj, join(''), map(cell_t), map(obj)); return row(columns);};
const addToTable = curry( function (elementId, rowInfo) { $(`#${elementId} tr:last`) .after(`<tr>${rowInfo}</tr>`); return $(`#${elementId} tr`).length - 1; });
![Page 35: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/35.jpg)
35
const addToTable = compose( appendToTable('personTable'), populateRow, props(['ssn','firstname’,'lastname']), findPerson, normalize, trim);
addToTable(personId);
Functional programming
![Page 36: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/36.jpg)
But what about errors?
![Page 37: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/37.jpg)
37
Containerizing
const Wrapper = function (val) { this._val = val; }; // MapWrapper.prototype.map = function (f) { return f(this._val); }; // Unitconst wrap = (val) => new Wrapper(val);
guarded
identity
map
identity returnsthe same value
Wrapper
![Page 38: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/38.jpg)
Containerizing2
const wrappedValue = wrap('Get Functional'); // extract the valueconst value = wrappedValue.map(toUpper).map(repeat(2)).map(identity);
value; //-> 'GET FUNCTIONAL GET FUNCTIONAL'
![Page 39: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/39.jpg)
• 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
// FunctorWrapper.prototype.fmap = function (f) { return wrap(f(this._val));};
![Page 40: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/40.jpg)
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
fmapWrapper
2
Wrapper
2
apply function
Wrapper
5
wrap
![Page 41: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/41.jpg)
41
What can we do with containers?
Wrap a potentially null value or a function that can cause the program to fail
![Page 42: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/42.jpg)
42
Software is unpredictable
Exception thrown but contained within the wrapper
Exception does not affect any other part of the system
![Page 43: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/43.jpg)
43
Software must be robust
Function throws an exception
Exception is propagated and gracefully handled
program flow
![Page 44: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/44.jpg)
44
Monads
Functor + Unit = Monad
…and some more
![Page 45: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/45.jpg)
45
Monads2• 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
![Page 46: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/46.jpg)
46
So call me: Maybe• Wall-off impurity• Consolidate null-check logic• Consolidated exception throwing• Support compositionally of functions• Centralize logic for providing default values
![Page 47: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/47.jpg)
47
Maybe Monad
Just
object
Nothing
Maybe
Just(value): represents a container that wraps a defined value.
Nothing(): represents a container that has no value, or a failure that needs no additional information.
![Page 48: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/48.jpg)
48
Maybe: Justclass 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; }}
![Page 49: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/49.jpg)
49
Maybe: Nothingclass 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; } }
![Page 50: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/50.jpg)
Usage
50
Maybe.of(3).map(plus2); //-> Maybe(5)
Maybe.of(3).chain(plus2); //-> 5
Maybe.fromNullable(null).map(plus2); //-> Nothing()
![Page 51: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/51.jpg)
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!');
![Page 52: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/52.jpg)
52
Monads abstract data flow+ Error Handling
trimxxx-xxx id normalize id findPerson
addToTable(personId)
nullpopulateRowLeft
nullLeft
appendToTable
orElse console.log
skipped skipped
props
skipped
When an error occurs, Maybe safely propagatesthe error through the components of your code
![Page 53: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/53.jpg)
To recap
![Page 54: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/54.jpg)
function addToTable(personId) { if(personId!= null) { personId= personId (/^\s*|\-|\s*$/g, ''); if(personId!== 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 not found!'); } } else { return 0; }}
Fromimperative
![Page 55: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/55.jpg)
55
To Functionalconst addToTable = compose( appendToTable('personTable'), populateRow, props(['ssn','firstname','lastname']), findPerson, normalize, trim);
addToTable('444-44-4444'); //-> Maybe(Student)addToTable('xxx-xx-xxxx'); //-> Maybe(null)addToTable('xxx-xx-xxxx').orElse( console.log('Error adding student'););
![Page 56: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/56.jpg)
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?
![Page 57: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/57.jpg)
My way of contributing and teaching
![Page 58: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/58.jpg)
Magazines
https://dzone.com/refcardz/functional-programming-with-javascript
![Page 59: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/59.jpg)
FunctionalProgramming in JavaScriptwww.manning.com/atencio
![Page 60: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/60.jpg)
Functional PHP
https://leanpub.com/functional-php
Free!
![Page 61: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/61.jpg)
@luijar
![Page 62: Thinking Functionally with JavaScript](https://reader035.vdocuments.net/reader035/viewer/2022070514/587fd2b11a28ab58248b4fcd/html5/thumbnails/62.jpg)
https://legacy.joind.in/16810
Thanks!