Brandon.Si(mmons)

code / art / projects

Haskell State of the Lens, Etc.

For my own purposes, I wanted to take a tour of all the various formulations of lenses on hackage and thought I would post the lightly-curated results here. I just grepped the package list page for the following terms: lens, label, record, accessor, editor, and reference. Some were not sufficiently general to include here.

Here were the ones implementing “lens-like” functionality, loosely in order of my opinion on their usefulness for my own purposes:

  • fclabels: straightforward, lenses built on underlying Point type, with support for lenses that can fail in ArrowZero
  • data-lens: uses natural a -> (s -> a, s) formulation for lens, leveraging category theory abstractions from the packages created after the breakup of Edward Kmett’s category-extras (a.k.a. the Big Bang)
  • partial-lens: the above but suppporting failure on the container
  • data-accessor: package description has nice background, implementation (not exported, oddly) is same as Data.Lens, apparently used to have wonky State monad implementation, seems from a similar school as “lenses” package
  • state-record: Lens type composed of simple setter/getter function pair, with TH generator and misc. functions for use with State monad
  • lenses: based on MonadState/StateT, odd formulation with no concrete type representation for the lens itself
  • edit-lenses: implementation of ideas from this paper with demos here, rather… involved
  • pointless-lenses: based on this paper. also rather involved, for instance here is a Lens (Tree a) [a]
  • recursion-schemes: another of EK’s packages. there’s allegedly a lens hiding here among the zygohistomorphic prepromorphisms (you think I’m joking)

For an analysis of various approaches to lenses which don’t necessarily have an implementation on hackage, these slides by Twan van Laarhoven were quite good, even without the accompanying talking human. Conal Elliot’s Semantic editor combinators pattern seems also relevant to mention here.

Here’s a list of the reverse dependencies for these, as a guage of popularity/general usefulness:

data-accessor 46
fclabels 33
data-lens 12
pointless-lenses 3
recursion-schemes 2

What about record-y packages?

As a bonus, here are the packages which attempt to augment or improve on records. I didn’t spend much time trying to grok these:

  • ixset: fancy indexable, groupable records gone wild
  • records: records as groupable name/value pairs, perhaps similar to ixset
  • has: entity-based records, looks novel but don’t understand it after a quick look
  • grapefruit-records: record system for grapefruit FRP, haven’t looked at implementation
  • fields: high-level interface and cute syntax for record operations, built on fclabels, unmaintained
  • setters: just generates “setter” functions for record fields using TH

My own thoughts

The appeal of lenses for me is that they offer a first-class setter/getter on which one can build abstractions and more powerful libraries, not simply save the programmer some key strokes. Lenses that simply throw an error when applied to the wrong constructor are not suitable for this purpose.

IMHO the only package above that provides a straightforward lens type for real algebraic data types is the seemingly unused ‘partial-lens’ variant on Data.Lens. In which the simplified representation is:

newtype Lens a b = Lens (a -> Maybe (b -> a, b))

The ‘fclabels’ package is great, but handles failure on set only w/r/t both the outer value and the inner value to be set. This means we can perform validation on a data type with its setter (cool!), but means we cannot partially apply a lens and get back a pure setter b -> a which is a real problem for me.

Comments