LTTP: point-free style with lodash

- 4 mins

I was first introduced to JavaScript’s array combinators through Underscore, which was a required Backbone.js dependency in the pre 1.0 days (that feels like a lifetime ago for frontend JavaScript). Back then, the ES5 methods on Array (map, filter, some, etc) were not widely supported among popular browsers. To compensate, frontend developers would include an array combinator shim for apps that targeted all major browsers, ensuring required functions would be available on the built-in object. Underscore served as an enhanced shim-plus-utility belt for working on arrays and object collections.

With underscore installed and a shimless app I would use write code like _.map(ls, function(){...}) rather than ls.map(function(){...}) directly and this was sufficient for a long time.

Eventually, a challenger library arrived in the form of lodash. Lodash initially offered many of underscore’s combinators and utility functions, but additionally focused on making them really performant. Since the library was largely API compatible, I along with many other JavaScript developers began using it for existing apps and greenfield development. I appreciated additional functions lodash provided like _.pull, _.indexBy (now _.keyBy), and chain, but didn’t dig too deeply into _.compose (now _.flow) or _.partial, even though chain emulated those functions’ behavior (if not outright being implemented via them). The basic combinators really helped with productivity and robustness, and I was happy with that.

Scala Interlude

I don’t recall exactly how I learned about Scala, but I do recall being smitten by it. It was my first proper introduction (long, very long introduction) to functional programming and I was absolutely captivated by the paradigm’s potential for programming productivity and safety gains.

Scala also made me sit down and seriously consider functional programming concepts that enjoyed less developer awareness than combinators. This includes using function composition as a first-class pattern in application and library development, in addition to other concepts that are frequently associated with it (Monads, Applicatives, etc.). I also developed a deep appreciation of function currying and partial application, which appeared harmonious with Scala’s first-class support for and default orientation towards immutable objects and its comprehensive collections API.

Back to JavaScript

Moving back to JavaScript land, I was brought back into the presiding frame of JS development which eschewed a mostly functional approach to development.

But during the summer of 2015 I made a perfunctory (and in retrospect ignorant) statement on the utility of partial application and function composition in JS, and received pushback from colleagues who had used it with great success. Later, while working on a primarily JavaScript codebase, I recalled their enthusiasm for the pattern and I decided to give it a whirl.

😑

It was nice. It was very nice. With _.flow, one can easy construct a portable pipeline of functions on an array. This solved the primary problem with _.chain at the time; namely, that it was restricted to a single array, and one would need to construct it anew for distinct arrays (this is no longer – and may have never been – the case. See plant).

// eg build an array from a heterogeneous array of ids, array of ids, and falsy values (let's say a missing id)

import uniq from 'lodash/uniq'
import compact from 'lodash/compact'
import flatten from 'lodash/flatten'

// flowRight composes functions from right to left: uniq(compact(flatten))
const uniqueIds = flowRight(uniq, compact, flatten)

// const arrayOfUncleanData = [1, 2, [3, 4, 5], [4, 5], undefined, 6, [7], …]
const ids = uniqueIds(arrayOfUncleanData)

The above function could easily (and probably should) be renamed to uniqueClean, since the pipeline is applicable to any array of values, or an array that contains falsey data that should be excluded. If you need to transform the array applied to the pipeline, just reach for lodash’s property for objects, one of the string functions (e.g., toLowerCase, etc), operations on numbers, or supply your own function.

// import …
const cleanSquare = flowRight(partialRight(map, n => n*n), uniq, compact, flatten)
const reallyImportantValues = [22, undefined, [42, 29, 10], 28, 45, 31, 101]
cleanSquare(reallyImportantValues)

Fully embracing this pattern in javascript has led to much more declarative code, which is much easier to read and in my experience generates far fewer bugs. It does come with the (potential) cost of function call overhead, but the vast majority of my use of function pipelining has not had to reckon with this limitation.

Crisson Jno-Charles

Crisson Jno-Charles

Fullstack Software Engineer specializing in Scala, JavaScript, and Java development

comments powered by Disqus
rss facebook twitter github youtube mail spotify instagram linkedin google pinterest medium vimeo