Skip to content

Instantly share code, notes, and snippets.

@bigs
Last active November 24, 2019 00:55
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save bigs/6923187 to your computer and use it in GitHub Desktop.
Save bigs/6923187 to your computer and use it in GitHub Desktop.
Musings on Lenses

Cole Brown

SPJ recently gave a fantastic talk on Edward Kmett's wildly useful lens library. Simon,a brilliant programmer and one of Haskell's designers, had little to no experience with lens prior to this talk and, resultingly, is able to offer a shockingly fresh perspective.

In his talk, he walks the audience through his deconstruction of the library — an illuminating journey. There is a lot of insight exposed, but there was one (perhaps unspoken) sentiment that struck me:

Functional programmers tend to prefer simple, versatile data structures like lists and trees. The reasoning is often times simple: simple data types yield powerful abstractions. One can implement a mind-boggling number of algorithms using maps and folds over lists (and associative lists).

While Haskell caters to this simplified model of programming, Haskell's type system and record syntax also encourage the use of abstract data types. These data types allow Haskell programmers to write semantically meaningful, strong, complete code, but they can make it more cumbersome to write the elegant and abstract code most functional programmers are used to.

This is where lens comes in. By providing incredibly powerful abstractions for viewing, modifying and traversing abstract data types, lens allows programmers to harness the power of functional constructs (like maps and folds) in the more explicit context of abstract types. It is of no surprise that the definition of a Lens is rather closely tied to Functor.

Looking more closely, a Lens is quite similar to a hylomorphism, sometimes known as a refold. Lenses describe the manner in which a given data structure is traversed/expanded (anamorphism) to a specific sub-record and then reconstructed (catamorphism) — the manner in which a data structure can be "unrolled" and then "rolled back up".

In the case of setters, this is fairly easy to grok: you use this recipe to get to the value you're seeking, set it to something new, then roll up a new object with that value modified. Getters, as Simon does a lovely job demonstrating, are slightly less intuitive. After traversing to the desired sub-record, the getter cheats the "roll up" phase by using the Const data type which throws away the rest of the data structure during the reconstruction process.

The icing on the cake is that lenses are composable — simply and truly. It is this quality that speaks to the essence of functional programming. Simple lenses can be composed to create larger, more powerful lenses.

At the end of his talk, Simon gives a quick example of a simple, readable lens that will traverse an HTML AST, updating all anchor tags with a certain class (or something to that effect, I'm having trouble reloading the video). With power like that (especially in the context of a type-safe language!), it's no surprise that lens is colloquially referred to as the jQuery for abstract data types.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment