Reputation:
Look at this thing from the documentation:
type ErrorAndStateWithIO e s a = ErrorT e (StateT s IO) a
==> ErrorT (StateT s IO (Either e a))
==> ErrorT (StateT (s -> IO (Either e a,s)))
I attach also constructor of ErrorT
:
Constructors
ErrorT
runErrorT :: m (Either e a)
The thing that I can't understand is a thing on the top of my post. What does it mean? For me it means that ErrorT e (StateT s IO) a = ErrorT (StateT s IO (Either e a))
. What's up? It is something like auto call constructor (runErrorT
)?
The second thing that bothers me: We know form of StateT
as StateT s m a
. Here, we have StateT s IO
. Where is a
parameter?
And last thing - can somebody explain how to run this monad?
Upvotes: 1
Views: 67
Reputation: 44603
The author of the documentation is playing fast and loose with notation. They're replacing the types ErrorT
and StateT
with their constructors, which also have the names ErrorT
and StateT
. (It makes some sort of sense because they're newtype
s.) The point the author is trying to make is that ErrorAndStateWithIO e s a
is equivalent to s -> IO (Either e a, s)
; it just has a couple of newtype
wrappers around it.
Looking at the definitions of those types,
newtype ErrorT e m a = ErrorT { runErrorT :: m (Either e a) }
newtype StateT s m a = StateT { runStateT :: s -> m (a, s) }
you can see that in the first step the outer ErrorT
has been replaced with its definition, and in the second the inner StateT
has been replaced with its definition.
Here, we have
StateT s IO
. Where isa
parameter?
ErrorT e
is a monad transformer, which means it transforms monads into other monads. Monads always have a kind of * -> *
; monad transformers have a kind of (* -> *) -> (* -> *)
. StateT s
is also a monad transformer. Here, StateT s
is being applied to IO
to produce a new monad (which is IO
augmented with state-management capabilities), and then ErrorT e
is being applied to that to produce another monad (which is StateT s IO
augmented with error-handling capabilities).
Can somebody explain how to run this monad?
As I mentioned above, ErrorAndStateWithIO e s a
is just s -> IO (Either e a, s)
with a couple of newtype
wrappers around it. So to run it you'd unwrap the newtype
s, pass in an s
, plumb it into an IO computation and scrutinise the result.
myComputation :: ErrorAndStateWithIO String Int Char
myComputation = -- ...
main = do
(result, _) <- runStateT (runErrorT myComputation) 5
case result of
Left err -> putStrLn err
Right result -> putStrLn $ "Success: " ++ [result]
Upvotes: 1