Personal tools

Performance/Monads

From HaskellWiki

< Performance(Difference between revisions)
Jump to: navigation, search
Line 3: Line 3:
 
== Unroll your MTL stacks ==
 
== Unroll your MTL stacks ==
   
MTL is an excellent for programming with monads, however stacked monad transformers do not inline well and can often impose a performance hit of up to 300% (your code will run up to three times slower).
+
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.
 
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.

Revision as of 08:47, 24 July 2007

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 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.