我有一个制作人:
p :: Producer Message IO r
.
我可以处理所有的消息使用:
runEffect $ for p processMessage
,
processMessage :: Message -> Effect IO ()
.
我如何实现有状态处理使用如下:
processMessage :: Message -> Effect (StateT MyState IO) ()
?
简短回答:
- 修改你的生产者,使其与它在 中运行的单子无关
- 你的
processMessage
很好 runEffect
返回StateT MyState IO ()
,你需要计算它
用一个假的例子回答更长的问题:
您的生产者被锁定在IO
单子中,您需要将其修改为MonadIO m
或显式状态单子。
import Control.Monad.State
import Pipes
type Message = Int
p :: MonadIO m => Producer Message m ()
p = each [1..10]
你的processMessage
签名已经没问题了。我遵循您的签名并添加一些简单的逻辑来执行IO和State功能
processMessage :: Message -> Effect (StateT MyState IO) ()
processMessage msg = do
modify (+ msg)
liftIO (print msg)
然后是最后一步。runEffect :: Monad m => Effect m r -> m r
,如果你用一个具体的类型代替m
,这最终是runEffect :: Effect (StateT MyState IO) () -> StateT MyState IO ()
,这意味着你将留下仍然需要执行的状态单子。执行状态单子有三种变体:runStateT
、evalStateT
和execStateT
。在这个例子中我选择了execStateT :: StateT MyState IO () -> IO MyState
变体,但是根据您的情况选择您需要的。
main :: IO ()
main = do
st <- execStateT (runEffect $ for p processMessage) 0
putStrLn $ "End state: " <> show st