Performance/Monads

From HaskellWiki
Jump to navigation Jump to search
Haskell Performance Resource

Constructs:
Data Types - Functions
Overloading - FFI - Arrays
Strings - Integers - I/O
Floating point - Concurrency
Modules - Monads

Techniques:
Strictness - Laziness
Avoiding space leaks
Accumulating parameter

Implementation-Specific:
GHC - nhc98 - Hugs
Yhc - JHC

Unroll your MTL stacks

MTL is an excellent for programming with monads, however stacked monad transformers do not inline well and often impose a performance hit of up to 3X.

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
newtype DRMonad a e s w = 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')