Reputation: 3358
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)
Upvotes: 1
Views: 310
Reputation: 8199
These are just cases of fmap. These are all equivalent:
getQthresh = qthresh <$> ask
getQthresh'' = fmap qthresh ask
getQthresh''' = liftM qthresh ask
getQthresh' = do
c <- ask
return (qthresh c)
The Data.Functor
/ Control.Applicative
version 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 which fmap/<$>
gives you. If you are forever writing <$> ask
you can define
get field = field <$> ask
Maybe that's what you were looking for now that I think of it. Then
get qthresh
will be the same as your
getQthresh
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:
get field = do
c <- ask
return (field c)
For the specific case of Reader
there is asks f
which is fmap f ask
, and likewise gets
for State
, but I was taking the question to be about 'lifting' accessors into a functor or monad, since it seemed it wasnt plain that do {x <- action; return (f x)}
is just f <$> action
Upvotes: 8