Трубы `работают` с состоянием

У меня есть продюсер:

p :: Producer Message IO r.

Я могу обрабатывать все сообщения, используя:

runEffect $ for p processMessage

куда

processMessage :: Message -> Effect IO ().

Как я могу реализовать обработку с сохранением состояния, используя что-то вроде:

processMessage :: Message -> Effect (StateT MyState IO) () ?


person krokodil    schedule 17.02.2021    source источник


Ответы (1)


Краткий ответ:

  1. Измените своего производителя, чтобы он не зависел от монады, в которой он работает.
  2. Ваш processMessage в порядке
  3. 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 уже в порядке. Я следую вашей подписи и добавляю простую логику для реализации функций ввода-вывода и состояния.

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
person Masse    schedule 17.02.2021