Editing records with lenses
I’m currently working on a Dominion simulator in Haskell which requires a few constantly changing records to accurately represent the game-play. While I first looked at using functions that returns updated records, I realized this would get complex as the records became more nested and the multiple functions per update complicated rather simple logic.
What I wanted to do is just update a records field in the ‘cleanest’ way possible with minimal line noise. That’s when I started looking at Lens, a Haskell library that lets you have CRUD-like access to deeply nested record types. After battling the usual Haskell jargon for an afternoon I got a few of the simpler lenses working and thought I’d store them here for the next time I need them.
The combinators in Control.Lens provide a highly generic toolbox for composing families of getters, folds, isomorphisms, traversals, setters and lenses and their indexed variants. - Huh?
First we declare our imports, language extensions, and create a new record type.
There’s a little magic going on here. First we mark a record to be lens’d by adding makeLenses ''<recordName>
. We then mark each field in that record to be lens’d by prepending them with underscores. After this we can get, set, and general update complex records in a much simpler way (albeit with some pretty interesting syntax choices).
You can also use Lenses on other datatypes too. For example if you wanted to get the third character of “Lenses” you could write "Lenses" ^? ix 3
. Told you the syntax was interesting right?
You can read more about Lens here or Edward Kmetts FAQ here.