Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ForkIO with a stateT

Tags:

haskell

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
like image 648
Akshat Avatar asked Jul 09 '26 07:07

Akshat


1 Answers

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.

like image 194
shang Avatar answered Jul 13 '26 15:07

shang