ForkIO with a stateT

haskell

Solution

You cannot have a `State` computation running in multiple threads sharing the same state because behind the scenes, the `State` monad is nothing more than a chain of function calls that passes the state value on to the next function in the chain.

For multithreaded code you can replace `StateT s IO` with `ReaderT (IORef s) IO` and use

forkIO $ runReaderT (h event) stateVar

to fork new threads (where `stateVar` is an `IORef` that contains the shared state).

Inside the `ReaderT` stack, you read the current shared state with

stateVar <- ask
s <- lift $ readIORef stateVar

and update it with

stateVar <- ask
lift $ atomicModifyIORef stateVar f

where `f` is a pure function that takes the current state and returns the modified state plus an auxiliary result.

If you need anything more fancy (e.g. modify the state using monadic functions), then you should use either `MVar` or `TVar` instead of `IORef`.

Problem

How can we make a user pass an eventHandler, which uses a stateMonad but is invoked in a separate thread? For example the in the following example, how should the forkIO be called so that eventHandler can invoke operate? I am new to Haskell, please correct me if this is a wrong api to expose to users? ``` data MyTypeResult a = MyTypeValue a data MyTypeState = MyTypeState {_counter :: Int} newtype MyType a = MyType { unMyType :: StateT MyTypeState IO (MyTypeResult a) } instance Monad MyType where (>>=) = myTypeBind return = myTypeReturn fail = myTypeFail myTypeBind = undefined myTypeReturn = undefined myTypeFail = undefined type Event = String type Handler = Event -> MyType () doSomethingAwesome :: MyType Event doSomethingAwesome = undefined operate :: String -> MyType () operate = undefined start :: Handler -> MyType () start h = do event <- doSomethingAwesome --forkIO $ h event -- The line that is troubling return () testHandler :: Event -> MyType() testHandler _ = operate "abcd" myMain = start testHandler ```

Original source