J Fritsch
J Fritsch

Reputation: 3358

How to remove boiler plate code

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

Answers (1)

applicative
applicative

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

Related Questions