What's a monad transformer? I kind of know what a monad is, but what is a transformer? Functional programming sure does use some scary words. I guess OOP has it's fair share as well, with inheritance, subclasses, superclasses (which are much more super than your lowly subclass apparently), etc.
If a monad is like giving some additional context to a value:
Maybe a: "Either it's a value or nothing"
[a]: "The value was obtained from a list of possible values"
IO a: "The value was obtained from a database somewhere"
Except ErrorType a: "The value is either an error message or a real value"
, then a monad transformer takes an existing monad and augments it with even more context:
ExceptT ErrorType IO a: "this value was obtained from a database somewhere, and also maybe there was an error message"
StateT ConnectionPool IO a: "this web server response value was calculated using a connection obtained from the server's stateful connection pool, and a database connection"
Most monads like State are actually defined as the monad transformer applied to the Identity monad, which has no special context at all:
State stateType returnType = StateT stateType Identity returnType
Additionally, IO is very common to bury at the bottom of one of these stacks, so there is 'liftIO' to run an IO action in a monad transformer stack. So your web server can just do:
liftIO $ putStrLn "Hello World"
if you need a quick log message. You need liftIO, because 'putStrLn "Hello World"' is of type IO (), and the web server needs type 'StateT ConnectionPool IO ()'.
Note: IO does more than just databases, of course.
I like to think of it as a way to combine monads. Two classic examples might be the State monad and the Maybe monad.
So let's say you want to create a function that operates on some state and might return a value. These are clearly both monads that you've heard about in Haskell, but how do you use them together? The answer is to use a monad transformer.
StateT is the state monad transformer that takes any other monad and adds state to it.
`StateT s m a' is a monad that adds a state of type s to a monad m. So `StateT Int Maybe a' is thing that when given an int which is its state, might return a value.
This particular combination was a little esoteric, so I'm not sure what a great example of this would be. However, you could also think of a situation where you want to have some sort of read-only state (such as flags from the command line) and the ability to write to a log.
In Haskell these are provided by the Reader and Writer monads. But again, you have two separate monads here and in order to actually make use of them, you'll need to combine them somehow. Enter a monad transformer. You can either transform a Writer monad with the ReaderT monad transform or transform a Reader monad with the WriterT transform.
ReaderT r (Writer w) a
OR
WriterT w (Reader r) a
Both satisfy this use case. I think those two constructions should be equivalent and conceptually equal. Someone should correct me if I'm wrong and there is some actual reason that those are different. To my understanding, the difference is purely due to limitations of the language as opposed to the mathematical constructs.
There's also the RWS monad, that rolls in Reader, Writer, and State one big monad. It's useful for servers and other applications: Configuration is Reader, changing state is in State, and log messages go to Writer.