我们如何让用户传递一个eventHandler,它使用stateMonad但是在一个单独的线程中调用?例如,在以下示例中,应该如何调用forkIO以便eventHandler可以调用操作?我是Haskell的新手,请纠正我,如果这是一个错误的API暴露给用户?
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
Run Code Online (Sandbox Code Playgroud)
你不能State在多个共享相同状态的线程中运行计算,因为在幕后,Statemonad只不过是一个函数调用链,它将状态值传递给链中的下一个函数.
对于多线程代码,你可以替换StateT s IO使用ReaderT (IORef s) IO,并使用
forkIO $ runReaderT (h event) stateVar
Run Code Online (Sandbox Code Playgroud)
叉新线程(其中,stateVar是IORef包含共享状态).
在ReaderT堆栈内部,您可以使用读取当前的共享状态
stateVar <- ask
s <- lift $ readIORef stateVar
Run Code Online (Sandbox Code Playgroud)
并用它更新
stateVar <- ask
lift $ atomicModifyIORef stateVar f
Run Code Online (Sandbox Code Playgroud)
where f是一个纯函数,它接受当前状态并返回修改后的状态加上一个辅助结果.
如果你需要更多花哨的东西(例如使用monadic函数修改状态),那么你应该使用MVar或TVar代替IORef.