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 inArrowZero
- 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’scategory-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:
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.