I recently ran into the problem of fclabels partial lenses being partial in both directions. This was not a critical problem, but it was annoying that a type had to be Maybe when the code would never use the “Nothing” constructor. There’s a new, interesting lens library called YALL, that inspired me to think about it a bit more. There are some potential issues with this perspective – it is no longer clear that there are algebraic laws that hold. I think that there’s a possibility that this might be resolved by adding some restrictions on the relationship between m and w. Anyway, the point is that lens library design is not a settled issue.
I’m interested in trying another way of using template haskell to express lenses:
fstLens = [mkLens| \(a, _) -> a |] sndLens = [mkLens| \(_, b) -> b |] fooLens = [mkLens| \(Just (a, b)) -> [a, b] |] tupListIso = [mkIso| \(a, b) = [a, b] |]
Each lens is specified in terms of the implementation of its get. We can do this because construction literals are bidirectional – they can be used for pattern matching. The right hand side of the lenses need to have variables in every position in order to preserve the lens laws (otherwise a portion of the set would not be reflected in the corresponding get).
The partiality of the lenses depends on whether any of the types used have multiple constructors – whether a match could fail. If the constructor on the left could fail, then the lens is partial in both directions (so fooLens is fully partial). If the constructor on the right could fail, then the lens is at least partial in the setter.
We can also bring in function application:
plusOneLens = lens (+1) (const . subtract 1) switchPlus = [mkLens| \(a, b) -> (plusOneLens b, plusOneLens a) |]
This is moving towards a full-blown embedded language for creating bidirectional transformations! It’d be interesting to target the feature set of the Boomerang project, which has a particular focus on doing bidirectional operations with text, and can do so with regexes as well as more powerful grammars. I’ve already written a TH quasi-quoter that allows you to use regular expressions in patterns and expressions: rex. Incorporating this into lens generation, by adding cannonical serialization to regexes, would be really cool.
I think that this way of working with lenses / isos would really help to popularize their use in Haskell. While fclabels is quite excellent, the Applicative instance is not a very clear way to construct lenses on compound structures. This is even nice for the typical lenses, as it avoids using typical records in the first place. Though, foobar_ can be nicer than get foobar.