Performance/Monads
Haskell Performance Resource
Constructs: Techniques: |
Unroll your MTL stacks
MTL is an excellent library for programming with monads. However stacked monad transformers do not inline well and the library is in need of an optimization pass. As a result, it can often impose a performance hit of up to 300% (your code will run up to three times slower).
If you care about this, the best option is to flatten you stack of transformers into a single, hand unrolled monad. An extreme example follows.
This is a typical MTL monad stack
newtype DRM a = DRM {unDRM:: ErrorT Finish (RWS () DNA RNA) a} deriving (MonadState DNA, MonadWriter RNA, MonadError Finish, Monad)
We can unroll it as follows:
type DRM = DRMonad Finish DNA RNA
newtype DRMonad e s w a = DRMonad {runDRMonad :: s -> (Either e a,s,w)}
instance (Monoid m, Error e) => Monad (DRMonad e s w) where
return x = DRMonad(\s -> (Right x, s, mempty))
(>>= = bindDRMonad
fail _ = DRMonad (\s->(Left e,s,mempty))
{-# INLINE bindDRMonad #-}
{-# INLINE bindDRMonad2 #-}
bindDRMonad :: Monoid m => DRMonad a e s w -> (a -> DRMonad b e s w) -> DRMonad b e s w
bindDRMonad m f = DRMonad$ \s -> case runDRMonad m s of
(x',s',w) ->
bindDRMonad2 x' (s',w,f)
bindDRMonad2 x' (s',w, f) = case x' of
Left e -> (Left e, s', w)
Right r -> case runDRMonad (f r) s' of
(x'',s'',w') ->
(x'', s'', w `mappend` w')
After this, you will also want to add the instances for MonadState, MonadWriter, etc.