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&#39;)  <- runAccumT mf w
      (v, !w&#39;&#39;) <- runAccumT mv (w `mappend` w&#39;)
      return (f v, w&#39; `mappend` w&#39;&#39;)
    {-# INLINE (<*>) #-}

instance (Monoid w, Functor m, Monad m) => Monad (AccumT w m) where
    m >>= k  = AccumT $ \ !w -> do
        (a, !w&#39;)  <- runAccumT m w
        (b, !w&#39;&#39;) <- runAccumT (k a) (w `mappend` w&#39;)
        return (b, w&#39; `mappend` w&#39;&#39;)
    {-# 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 using put $! s or modify&#39;. 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 for AccumT, basically removing all the tildes from the pair matches as strict StateT 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 for StateT making state modifications strict can be handled only at puts and with a strict modify&#39;.

  • 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 mappends as well.