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.

One things to note about the original code is that it must constantly check the returned value even though a failure (Nothing) is most likely a rare occurrence, and further more it's possible that we will need to propagate a Nothing through an arbitrary large amount of code, though a lot of times this won't happen.

Ideally, we want "failure free" code to run as normal and only deal with failure when it occurs and immediately fail in those cases rather than propagating the failure. This is what using continuation passing style gets us.

There are two things to note about this code. mplus is where we use the case analysis. mplus is the only place that we look at what was returned and to do it we have to actually run the computation. This means that we only deal with "effects" when we need to. Further, mzero discards its continuation. This is the typical pattern for aborting a computation in CPS and will lead to an immediate termination of the computation.

MaybeCPS should be faster than using Maybe in most cases and should be almost a drop in replacement for Maybe. Unfortunately, this may not necessarily be true. Usually, using a CPS implementation would be a drop in replacement, but Maybe is not an abstract data type. Anyway, some results for a more complicated example are here.