Performance/Monads
Jump to navigation
Jump to search
Haskell Performance Resource
Constructs: Techniques: |
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')