I would like to reduce the following boiler plate code, BUT without using lenses (Data.Label). How could I best do this?
data Qcfg = Qcfg { qthresh :: Int, tdelay :: Rational, cwpsq :: TPSQ, cwmap :: TMap, cwchan :: TChan String }
getQthresh = do
c <- ask
return (qthresh c)
getDelay = do
c <- ask
return (tdelay c)
getTMap = do
c <- ask
return (cwmap c)
getTPsq = do
c <- ask
return (cwpsq c)
getTChan = do
c <- ask
return (cwchan c)
These are just cases of fmap. These are all equivalent:
The
Data.Functor/Control.Applicativeversion with<$>is the one you want; there is no boilerplate in it at all if you think about it. And you are indeed wasting space writing functions for each accessor; you just a new way to apply the accessors whichfmap/<$>gives you. If you are forever writing<$> askyou can defineMaybe that’s what you were looking for now that I think of it. Then
will be the same as your
and similarly for the other fields. Of course you could define this
get(note that State goes with a different one) in your monadic way:For the specific case of
Readerthere isasks fwhich isfmap f ask, and likewisegetsforState, but I was taking the question to be about ‘lifting’ accessors into a functor or monad, since it seemed it wasnt plain thatdo {x <- action; return (f x)}is justf <$> action