Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any significant difference between StateT over Reader and ReaderT over State?

When I design my programming model I always have a dilemma which approach is better:

type MyMonad1 = StateT MyState (Reader Env)
type MyMonad2 = ReaderT Env (State MyState)

What are the benefits and trade offs between using one monad over another? Does it matter at all? How about performance?

like image 467
radrow Avatar asked Jun 02 '19 13:06

radrow


1 Answers

In the general case, different orderings of monad transformers will lead to different behaviors, but as was pointed out in the comments, for the two orderings of "state" and "reader", we have the following isomorphisms up to newtypes:

StateT MyState (Reader Env) a  ~  MyState -> Env -> (a, MyState)
ReaderT Env (State MyState) a  ~  Env -> MyState -> (a, MyState)

so the only difference is one of argument order, and these two monads are otherwise semantically equivalent.

With respect to performance, it's hard to know for sure without benchmarking actual code. However, as one data point, if you consider the following monadic action:

foo :: StateT Double (Reader Int) Int
foo = do
  n <- ask
  modify (* fromIntegral n)
  gets floor

then when compiled with GHC 8.6.4 using -O2, the newtypes are -- obviously -- optimized away, and this generates exactly the same Core if you change the signature to:

foo :: ReaderT Int (State Double) Int

except that the two arguments to foo get flipped. So, there's no performance difference at all, at least in this simple example.

Stylistically, you might run into situations where one ordering leads to nicer looking code than the other, but usually there won't be much to choose between them. In particular, basic monadic actions like the one above will look exactly the same with either ordering.

For no good reason, I tend to favor #2, mostly because the Env -> MyState -> (a, MyState) looks more natural to me.

like image 141
K. A. Buhr Avatar answered Nov 04 '22 19:11

K. A. Buhr