Optics from a Different Perspective
Why lenses don’t compose backwards
“How do I get to Aberdeen from here?”
“If I were going to Aberdeen, I wouldn’t start from here.”
I’m not sure that “lenses compose backwards” is still a live view. That said, I think this view is tied to some broader misunderstandings that are easy to fall into. The fact is that while lenses/optics are a really useful abstraction the historical (and often pedagogical) route leading up to them is really odd. We usually start by talking about getters and setters, but those are actually a somewhat awkward aspect of modern optics. My goal here is to present a different route to lenses that I think more directly captures the intuition behind them.
Semantic Editor Combinators
The starting point for this approach is an old Conal Elliott blog post about what he calls Semantic Editor Combinators. The basic idea is that when we think about functions like
map :: (a -> b) -> [a] -> [b]
first :: (a -> b) -> (a,c) -> (b,c)
we shouldn’t think of them as two argument functions that happen to be curried as a quirk of Haskell, but as genuinely single argument function that transform an “edit” from operating on a “smaller” structure to operating on a “larger” structure. Furthermore, we should be perfectly happy to compose these: map . first . map . first
takes an edit on a small structure and transforms it into an edit on a (much) larger structure.