To demystify Template Haskell, suppose you have
data Example a = Example { _foo :: Int, _bar :: a }
then
makeLenses 'Example
produces (more or less)
foo :: Lens' (Example a) Int bar :: Lens (Example a) (Example b) a b
There's nothing particularly magical going on, though. You can write these yourself:
foo :: Lens' (Example a) Int -- :: Functor f => (Int -> f Int) -> (Example a -> f (Example a)) ;; expand the alias foo wrap (Example foo bar) = fmap (\newFoo -> Example newFoo bar) (wrap foo) bar :: Lens (Example a) (Example b) a b -- :: Functor f => (a -> f b) -> (Example a -> f (Example b)) ;; expand the alias bar wrap (Example foo bar) = fmap (\newBar -> Example foo newBar) (wrap bar)
Essentially, you want to "visit" your lens' "focus" with the wrap
function and then rebuild the "entire" type.