Search code examples
haskelltemplate-haskelllenseshaskell-lens

Generating lenses for a "lens" library with a custom name processor instead of the default "underscore"-based one


The standard makeLenses implementation generates lenses for all the fields of a record which begin with underscore. I very much dislike the idea of having to introduce such an awkward naming convention to my records for many reasons. What I want to do is just generate lenses for all fields of a record and name them by just appending a suffix "L" to field names.

With an fc-labels library all I had to do to achieve that was

mkLabelsWith (++ "L") [''MyRecord]

but the lens library has a much more involved configuration with rulesets and stuff, which isn't as easy to get a mind around. So I'm asking for a specific recipe to just achieve the same thing.


Solution

  • Looking at the code, it seems pretty straightforward. LensRules have a function lensField :: String -> Maybe String (which either gives the name for a lens or fails). So you can make a function like

    myMakeLenses = makeLensesWith $ lensRules
      & lensField .~ (\name -> Just (name ++ "L"))
    

    and use that instead of makeLenses. Of course you could parameterize your function on (++ "L").

    Or you could write it inline if you prefer, e.g.

    makeLensesWith ?? ''Foo $ lensRules
      & lensField .~ (\name -> Just (name ++ "L"))
    

    (Note that (??) is just infix flip for passing the arguments in the right order. You can think of it as a "hole" in this case that the second argument get filled into. And (&) is just flipped ($).)