concrete functor and monad transformers
#89Offer stricter versions of AccumT
AccumT
is extremely lazy, much like lazy StateT
. I suspect that for most purposes, what users actually want is a version that's strict in the accumulator value. That would correspond to instances (at least approximately) like the following:
instance (Monoid w, Functor m, Monad m) => Applicative (AccumT w m) where
pure a = AccumT $ \ !_ -> return (a, mempty)
{-# INLINE pure #-}
mf <*> mv = AccumT $ \ !w -> do
(f, !w') <- runAccumT mf w
(v, !w'') <- runAccumT mv (w `mappend` w')
return (f v, w' `mappend` w'')
{-# INLINE (<*>) #-}
instance (Monoid w, Functor m, Monad m) => Monad (AccumT w m) where
m >>= k = AccumT $ \ !w -> do
(a, !w') <- runAccumT m w
(b, !w'') <- runAccumT (k a) (w `mappend` w')
return (b, w' `mappend` w'')
{-# INLINE (>>=) #-}
I think it's also plausible that some users will want a version that's strict in the result pairs, but not in the accumulators. Would you be open to offering the totally strict version, and perhaps the pair-strict version?
- description updated
The strict
StateT
is only strict in the pairs, which allows users to be strict in the state by usingput $! s
ormodify'
. It can be a bit messy, but it provides the minimal hook to allow users to control strictness of the state. It would make sense to do something similar forAccumT
, basically removing all the tildes from the pair matches as strictStateT
does.That would also make the CPS version of
WriterT
redundant.I don't really think the situation is analogous to
StateT
. It affects every bind, whereas forStateT
making state modifications strict can be handled only atput
s and with a strictmodify'
.You're right: strictness in the pairs isn't much use on its own and strictness in the accumulator is the way to go. We should probably be forcing the
mappend
s as well.