I've got this type alias:
type Board a = ReaderT String (StateT String IO) a
I know that StateT
has the kind * -> (* -> *) -> * -> *
so it should get three parameters. But in the above example, StateT
only receives String
and the IO
-Monad.
Now I'm wondering where the missing parameter is passed to StateT
.
Same goes for IO
which should get one parameter but doesn't get any.
If you look at the definition of ReaderT
, you will see that its second parameter is itself applied to its last parameter:
newtype ReaderT r m a = ReaderT { runReaderT :: r -> m a }
^^^
right here
Which means that its second parameter m
must have kind m :: * -> *
. And this is exactly what you get if you apply only two, not three, parameters to StateT
:
StateT :: * -> (* -> *) -> * -> *
StateT x y :: * -> *
(where x :: * and y :: * -> *)
When substituting the definition of ReaderT
in your type Board
, you'll get:
(1) type Board a = ReaderT String (StateT String IO) a
-- Substituting ReaderT definition (pseudocode)
(2) type Board a = { runReaderT :: String -> StateT String IO a }
^^^^^^^^^^^^^^^^^^
Look, StateT has all its three parameters!