Len Smith speaking at LibertyJS
November 17th, 2017

Live blog: functional programming in JavaScript, Len Smith

Tom Boutell
Chief Software Architect

I'm liveblogging Len Smith's talk on functional programming in JavaScript at LibertyJS. This is a live blog so bear with me. Thanks! — Tom

Functional programming has always been an option in JavaScript, but it really took off with React.

You have always been able to assign a function to a variable in JavaScript. ES6 made it a little simpler with the arrow function syntax. You can even write one-liners.

Functions can be parameters. Anyone who has used $.get or written a jQuery event handler knows how to pass a function to another function.

$.get('/items.json').then(function() {
  cool();
});

This is needlessly complicated, if we understand we're just passing a function and "cool" is defined elsewhere, we can just write:

$.get('/items.json').then(cool);

We can return functions from functions as well.

We'll look at lodash and Ramda today. lodash is not a pure functional library, it does mutate (modify) arrays sometimes. Ramda never does that. But sometimes "impure" functions, like debounce(), are handy.

"Reduce the unpredictable surface area." As in, be as pure as you can... when you can, accept arguments and return new values without modifying the arguments.

Advantages of pure functions:

Testable, portable, readable, parallelizable, and memoizable.

Testable: easy to test, you verify the right return value, you're done.

Portable: doesn't rely on code you can't see in the function, so you can move it.

Readable: nowhere else to look.

Parallelizable: you're not mutating state so you don't have to worry about locking and racer conditions.

Memoizable: 

Let's look at a function that provides its own cache for performance.

let cache = {}
const expensiveFunction = (x) => {
  if (cache[x]) {
    return cache[x]
  }

  const result = // do the hard expensive work here
  cache[x] = result
  return result
}

This works but it's a lot of redundant code. How about a memoize function?

const memoize = (func) => {
  let cache = {}
  return (x) => {
    cache[x] = cache[x] || func(x)
    return cache[x]
  }
}

Now we can just pass an ordinary function to memoize() to get a version sped up by a cache.

For loops

Java/C/C++ developers take this for granted but it's a lot of repetitive work:

for (i = 0; (i < foo.length); i++) {
  // do something with foo[i]
}

Compare that to JavaScript's native forEach method for arrays:

foo.forEach(val => {
  // do something with val
});

Building your own lodash/ ramda

gt = (x) => (y) => x > y

always = (x) => () => x

negate = (fn) => () => !fn()

T = always(true)

F = negate(T)

eq = (x) => (y) => x === y

notEq = negate(eq)

const identity = x => x

"What the heck is identity good for?" It's a good default value for an argument that is a function. If skipped you get a function that makes no change.

"In functional programming you want functions with an arity of one" (one argument).

const add = (x, y) => x + y

curriedAdd = (x) => (y) => x + y

addOne = curriedAdd(1)

addTwo = _.curry(add)(2)

The lodash-fp library is better for functional programming, in Len's opinion, becaus the function comes first and the data to be processed comes last. This makes currying more convenient and avoids awkward calls to _.partial().

In ramda, all of the methods are already curried. 

What the heck is currying? If you call add() with two arguments, you get the sum. But if add() supports currying, and you call it with one argument (the number 4), you get a new function that takes just one argument and adds 4 to that argument.

Why do we care about currying? It helps you get to a function that takes one argument, which means you can do stuff like call it with forEach() or _.map().

const playsEight = compose(gte(__, 8), prop('maxPlayers'))

What is __ doing here? It's a magic placeholder in ramda. We don't have a value yet for that one — we want it to be the one that is supplied by those calling the function gte() will return.

That is:

gte(__, 8)

Returns a new function that takes ONE argument and returns whether that argument is greater than or equal to 8.

See also:

http://tinyurl.com/libertypax

"What does compose do?" It will take multiple functions and compose them from right to left, creating a new function. The rightmost function is called with the arguments given, then the function to the left of it is called with that value, and the return value of that is passed to the next function... etc.

"Why is that useful?" It lets you build functions that will do something later when arguments are actually provided, like this code:

const playsEight = compose(gte(__, 8), prop('maxPlayers'))

This returns a new function that takes an object and returns true if its maxPlayers property is greater than or equal to 8. That function takes one argument so you can use it with forEach() and similar techniques.

 

Tom Boutell
Chief Software Architect

Check out another article