Another (IMO best in terms of usability) solution is to:
- Enable
DuplicateRecordFieldsandNoFieldSelectors, drop silly underscores. - Enable
OverloadedRecordDotfor field access. - Enable
OverloadedLabelsand use generic optics from theopticslibrary for field modification. You can also usegeneric-lensif you really want to stick withlens, but these are less efficient in terms of compile time (and sometimes runtime) performance.
Example:
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE OverloadedRecordDot #-}
module Record where
import GHC.Generics
import Optics.Core
data Record1 = Record1
{ foo :: String
, bar :: Int
} deriving Generic
data Record2 = Record2
{ foo :: Int
, bar :: String
} deriving Generic
fieldAccessExample1 :: Record1 -> String
fieldAccessExample1 r = r.foo
fieldModificationExample1 :: Record1 -> Record1
fieldModificationExample1 r = r & #foo .~ "hmm"
& #bar .~ 777
fieldAccessExample2 :: Record2 -> Int
fieldAccessExample2 r = r.foo
fieldModificationExample2 :: Record2 -> Record2
fieldModificationExample2 r = r & #foo .~ 123
& #bar .~ "hey"