diff options
Diffstat (limited to 'static/talks/fp-js/index.org')
-rw-r--r-- | static/talks/fp-js/index.org | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/static/talks/fp-js/index.org b/static/talks/fp-js/index.org new file mode 100644 index 0000000..8a4bf6c --- /dev/null +++ b/static/talks/fp-js/index.org @@ -0,0 +1,226 @@ +#+TITLE: Functional Programming in JavaScript +#+PROPERTY: :html-toplevel-hlevel 1 +#+PROPERTY: :with-toc 0 +* Why? + +Imperative programming is concerned with *how* + +Functional programming is concerned with *what* + +* Concepts + + - First-class Functions + - Higher-order Functions + - Recursion + - Pure functions + - Currying & Partial Application + +* Further concepts + + - Lazy Evaluation + - Types & Data Structures + - Category Theory + +* First-class functions + + - Have no restriction on their use + - Are values + - Enable the use of callback functions in JavaScript + + + +#+BEGIN_SRC js +const fn = function () { + return 2 +} +#+END_SRC + + +* Higher-order functions + +Functions that operate on other functions are higher-order functions + + + +#+BEGIN_SRC js +const succ = function (x) { + return x + 1 +} + +const arr = [1, 2, 3, 4] + +arr.map(succ) +#+END_SRC + +Here, =Array.prototype.map= is the higher-order function + +* Higher-order functions (cont.) + +Functions that return functions are also higher-order functions + + + +#+BEGIN_SRC js +function adder (n) { + return function (x) { + return n + x + } +} + +const add1 = adder(1) +#+END_SRC + +=adder= is a higher-order function + +* Pure functions + +Functions without side-effects + +#+BEGIN_SRC js +const succ = (x) => x + 1 + +console.log(succ(succ(1))) + +// could be optimised away by a compiler, e.g.: + +console.log(3) +#+END_SRC + +* Recursion + +Functions that call themselves + +#+BEGIN_SRC js +function fibonacci (n) { + switch (n) { + case 0: + case 1: + return 1 + default: + return fibonacci(n - 1) + fibonacci(n - 2) + } +} +#+END_SRC + +* Partial application + +The infamous =Function.prototype.bind= in JavaScript + +#+BEGIN_SRC js +function add (x, y) { + return x + y +} + +const add1 = add.bind(add, 1) + +add1(3) // = 4 +#+END_SRC + +* Partial application (cont.) + +After ES6 introduced arrow functions, partial application has become +more popular + +#+BEGIN_SRC js +const add = x => y => x + y +#+END_SRC + +* Currying + +Related to partial application, but more implicit and general + +Translates */1/ function of arity /n/* to */n/ functions of arity /1/* + +#+BEGIN_SRC js +function volume (w, d, h) { + return w * d * h +} + +const vol = curry(volume) +vol(10)(20)(30) +// is strictly equivalent to +volume(10, 20, 30) +#+END_SRC + +* Easy Currying + +In order to make currying (and partial application) easier to use, +move the *most important* argument to a function to the end: + +#+BEGIN_SRC js +const badMap = (arr, fn) => arr.map(fn) +const goodMap = (fn, arr) => arr.map(fn) +const curriedBadMap = curry(badmap) +const curriedGoodMap = curry(goodMap) + +const goodDoubleArray = goodMap(x => x * 2) +const badDoubleArray = badMap(_, x => x * 2) +#+END_SRC + +The bad version requires the curry function to support a magic +placeholder argument and doesn't look as clean. + +* Practical Currying + +Currying is not automatic in JavaScript, as in other languages + +External tools don't (currently) to statically analyse curried +functions + +Solution: Don't expose curried functions +Instead, write functions as if currying were automatic + +* Functional composition + +Creating functions from other functions + +Usually provided by =compose= (right-to-left) and =pipe= (left-to-right) + +A very simple definition of =compose= for only two functions would look like this + +#+BEGIN_SRC js +function compose (f, g) { + return function (...args) { + return f(g(...args)) + } +} +#+END_SRC + +* Functional composition (cont.) + +#+BEGIN_SRC js +const plusOne = x => x + 1 +const timesTwo = x => x * 2 + +const plusOneTimesTwo = compose(timesTwo, plusOne) +const timesTwoPlusOne = compose(plusOne, timesTwo) + +nextDoubled(3) // = (3 + 1) * 2 = 8 +timesTwoPlusOne(3) // = (3 * 2) + 1 = 7 +#+END_SRC + +* pipe + +What about =pipe=? + +=pipe= does the same thing, but runs the functions the other way around + +=pipe(f, g)= is the same as =compose(g, f)= + +* Point-free programming + +With currying and higher-order functions, we (often) don't need to declare function arguments + +#+BEGIN_SRC js +const modulo = a => b => b % a +const eq = a => b => a === b + +const isEven = x => eq(0)(modulo(2)(x)) +const isEvenPointFree = compose(eq(0), modulo(2)) +#+END_SRC + +* Further Resources + +- [[https://drboolean.gitbooks.io/mostly-adequate-guide/content/][Mostly adequate guide to FP (in javascript)]] +- [[http://ramdajs.com/][Ramda]], a general-purpose FP library +- [[https://sanctuary.js.org/][Sanctuary]], a JavaScript library for Haskellers |