У меня есть функция типа Map Int String -> Proxy () a () Void IO b
. Прямо сейчас он await
s делает все, что угодно, с полученным значением, а затем повторно вызывает себя. Я хотел бы изменить его так, чтобы он использовал State (Map Int String)
вместо того, чтобы передавать это в качестве аргумента, поэтому я могу просто использовать forever
и не нужно, чтобы каждая ветвь помнила о рекурсии. Я понимаю, что мне нужно использовать StateT
для объединения State
с другой монадой, но я не понимаю, где в этой сигнатуре типа принадлежит StateT
и нужны ли мне lift
функции, такие как get
. Какой правильный тип для функции, которая одновременно является State (Map Int String)
и Proxy () a () Void IO b
?
Как использовать состояние с трубами?
comment
Надеюсь это поможет! stackoverflow.com/ questions / 18471706 /
- person user3303858   schedule 13.02.2014
Ответы (1)
Примечание: Proxy () a () Void = Consumer a
, поэтому в этом ответе я буду называть его Consumer
.
Самый простой способ - поместить слой преобразователя монад StateT
за пределы слоя Consumer
и сразу же запустить его. Вот пример:
import Control.Monad (forever)
import Control.Monad.Trans.State.Strict
import Pipes
example :: (Show a) => Consumer a IO r
example = flip evalStateT 0 $ forever $ do
-- Inside here we are using `StateT Int (Consumer a IO) r`
a <- lift await
n <- get
lift $ lift $ putStrLn $ "Received value #" ++ show n ++ ": " ++ show a
put (n + 1)
... и вот как он ведет себя в действии:
>>> runEffect $ each ["Test", "ABC"] >-> example
Received value #0: "Test"
Received value #1: "ABC"
person
Gabriel Gonzalez
schedule
13.02.2014