【问题标题】:Pipes `run` with State带有状态的管道`run`
【发布时间】:2021-02-17 00:14:44
【问题描述】:
我有一个制作人:
p :: Producer Message IO r.
我可以使用以下方法处理所有消息:
runEffect $ for p processMessage
在哪里
processMessage :: Message -> Effect IO ().
我怎样才能使用类似的东西来实现有状态处理:
processMessage :: Message -> Effect (StateT MyState IO) ()?
【问题讨论】:
标签:
haskell
haskell-pipes
【解决方案1】:
简答:
- 修改您的生产者,使其对其运行的 monad 不可知
- 你的
processMessage 很好
-
runEffect 返回StateT MyState IO (),你需要评估它
更长的答案,一个虚拟的例子:
您的生产者被锁定在 IO monad 中,您需要将其修改为处于 MonadIO m 或显式状态 monad。
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 (),这意味着你将留下仍然需要执行的状态单子。执行状态 monad 有三个变体,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