about summary refs log tree commit diff stats
path: root/static/talks/fp-js/index.org
diff options
context:
space:
mode:
Diffstat (limited to 'static/talks/fp-js/index.org')
-rw-r--r--static/talks/fp-js/index.org226
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