8

I mean why doesn't it come the last?

Because of this convention to evaluate a transformer stack one has to write an awkward thing like that:

runStateT (runReaderT (runRWST stack r s) r') s'

instead of:

runStateT s' $ runReaderT r' $ runRWST r s $ stack

And combining it with immediate do becomes all the more awkward:

let 
  action = do
    liftIO $ putStrLn "Do"
    liftIO $ putStrLn "something"
  in runStateT (runReaderT (runRWST action r s) r') s'

instead of:

runStateT s' $ runReaderT r' $ runRWST r s $ do
  liftIO $ putStrLn "Do"
  liftIO $ putStrLn "something"

Does this have any motivation behind or is this just an unfortunate convention?

BTW, I do realize that the current convention makes it easy to implement the "run" function using the record syntax, but this can't be an argument, since libraries must prefer usability to easiness of implementation.

Nikita Volkov
  • 42,792
  • 11
  • 94
  • 169
  • Maybe an infix notation, like the chain ``(stack `runRWST` r) s `runReaderT` r' `runStateT` s'``, would be more intuitive? Still want to remove the remaining parentheses, though. – Gassa Mar 27 '14 at 07:18
  • I like ``(`runStateT` s') . (`runReaderT` r') $ do { ... }``. Doesn't quite work with `RWST` unfortunately, you'd need to use `flip (uncurry runRWST) (r, s) $ do { ... }`. – leftaroundabout Mar 27 '14 at 19:44
  • @leftaroundabout I'm not actually looking for optimizations to the example code, but fundamental reasons of the design decisions behind the "transformers". I need to decide whether to follow these conventions when designing custom transformers. – Nikita Volkov Mar 27 '14 at 20:00

3 Answers3

4

In the HaskellWiki entry for Parameter order and in this Stack Overflow question, there are two recommendations for parameter order:

In my experience with the Reader/State monad, The same computation is invoked on different environments/states more frequently than different monadic computations are invoked on the same environment/state. The current parameter order is convenient for that.

Another reason: Reader/State monadic values behave very much like functions that take an environment/the initial state as parameters. And in Haskell functions go before parameters.

To avoid the necessity of nested ReaderT/StateT/RWST transformers, you can work on with a single RWST transformer carrying global state/environment, and use zoom and magnify from the lens library to adapt computations that work in more restricted environments.

Community
  • 1
  • 1
danidiaz
  • 26,936
  • 4
  • 45
  • 95
  • Well, the "most varying" argument could only support the primitive cases and it already fails for `RWST`, because that one has 3 params. Concerning the transformer stacks it is definitely only the stack that can be most varying. So, this is hardly an explanation. Also, I'm not asking about `ReaderT` or `RSWT`, but the general pattern for design of all kinds of monads. Be it `ConnectionT` or `SessionT` or whatever. – Nikita Volkov Mar 27 '14 at 20:21
3

I'm sure there's an element of expedience to it. It's very easy to define

newtype StateT = StateT { runStateT :: s -> m (a, s) }

and be done with it.

Tom Ellis
  • 9,224
  • 1
  • 29
  • 54
  • As mentioned in the question, "this can't be an argument, since libraries must prefer usability to easiness of implementation". – Nikita Volkov Mar 27 '14 at 09:33
  • On the contrary, it can be an argument, as it eases the implementation of the library. It is arguably nicer for some applications too (though I generally would much prefer the argument coming last, as this aids in my typical use of such data types.) – Thomas Eding Mar 29 '14 at 00:01
0

I'd like to add consistency as the answer to the mix. This is all speculation, so take this with a grain of salt:

The initial implementations used newtype record syntax to write these data definitions, so the data comes first when running it, oblivious as to whether or not this is preferable to the data coming in as the last argument. Newer data types simply follow this convention.

Thomas Eding
  • 35,312
  • 13
  • 75
  • 106