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.
shachaf's answer doesn't work with lenses 4.4+ which changed the template-haskell related APIs.
Here is the implementation that works with those versions:
import Language.Haskell.TH
myMakeLenses :: Name -> DecsQ
myMakeLenses = makeLensesWith $ lensRules
& lensField .~ \_ _ name -> [TopName (mkName $ nameBase name ++ "L")]
(this is 4.5+, in 4.4 the lambda would take only \_ name
as parameters)
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 ($)
.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With