why are the state and reader monads functions while the writer monad is a tuple?

The state and reader monad both depend on the value of whatever state we're interested in. We need to be able to access it otherwise how could we write something like

foo = do
 i <- get
 return $ if i == 1 then 2 else 3

So our state monad naturally looks like something that takes in a state, does stuff, and produces a new one.

Likewise with the reader monad, we take in some state, magic, and produce an output (but no new state since it's Reader s a <=> s -> a.

Now this is very different than the writer monad. In the writer, we don't care about what's been stuck in the state previously, all we want to do is take our current state, and jam some more stuff in there. Because our state is a monoid, we have a guaranteed start state mempty and a way to jam stuff in mappend. This means that we can "run" each computation in an empty context so to speak and just fuse the outputs together and get identical results.

Ok, now there's about a few questions so I'll go one at a time

  1. If the writer monad had access to the previously written results, then it's going to look like s -> (s, a) which is the state monad :) So yes, whatever you could do with the state monad could be done with this augmented writer.

    In fact both the StateT and WriterT monads have MonadPlus instances so I'm not sure what you're getting at here..

  2. Since there isn't an arbitrary function m a -> a, we need some way to unwrap a computation to view the results ala >>=, and since return :: a -> m a makes it trivial to go the other way, it's more general to go from plain to monadic value. Otherwise we'd just have these useless IO String, STM Int and whatnot that we couldn't depend on for the rest of our computation since fmap won't let us hoist in more side effects.


They're defined differently because they do different things.

Take the reader monad. Start by thinking about what it means, not about how it works.

A computation in the reader monad is one that depends on an extra piece of information, the reader's "environment". So a Reader Env Int is an Int that depends on the environment (of type Env); if I evaluate it with one environment I'll get one Int value, and if I evaluate it with a different environment I'll get another Int value. If I don't have an environment I can't know what value the Reader env Int is.

Now, what kind of value will give me an Int if I give it an Env? A function of type Env -> Int! So that generalises to e -> a being a monad for each e (with a being the type parameter of the monad; (->) e if you like the prefix notation).

Now lets think about the meaning of the writer monad. A computation in the writer monad produces a value, but it also produces an extra value "on the side": the "log" value. And when we bind together a series of monadic computations from in the writer monad, the log values will be combined (if we require the log type to be a monoid, then this guarantees log values can be combined with no other knowledge about what they are). So a Writer Log Int is an Int that also comes with value of type Log.

That sounds a lot like simply a pair: (Log, Int). And that generalises to (w, a) being a monad for each w (with a being the type parameter of the monad). The monoid constraint on w that guarantees we can combine the log values also means that we have an obvious starting value (the identity element for the monoid: mempty), so we don't need to provide anything to get a value out of a value in the writer monad.

The reasoning for the state monad to be s -> (a, s) is actually pretty much a combination of the above; a State S Int is an Int that both depends on an S value (as the reader depends on the environment) and also produces an S value, where binding together a sequence of state computations should result in each one "seeing" the state produced by the previous one. A value that depends on a state value is a function of the state value; if the output comes "along with" a new state value then we need a pair.