Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use State with Pipes?

I have a function with a type Map Int String -> Proxy () a () Void IO b. Right now it awaits, does whatever with the value it got, and then re-calls itself. I'd like to change it to use State (Map Int String) instead of having that passed as an argument, so I can just use forever and don't need to have every branch remember to recurse. I get that I need to use StateT to combine State with another monad, but I don't understand where in that type signature the StateT belongs, or whether or not I need to lift functions like get. What is the correct type for a function that is both a State (Map Int String) and a Proxy () a () Void IO b?

like image 643
user3261399 Avatar asked Feb 13 '14 02:02

user3261399


1 Answers

Note: Proxy () a () Void = Consumer a, so I will refer to it as a Consumer for this answer.

The simple way is to put your StateT monad transformer layer outside of the Consumer layer and then run it immediately. Here is an example:

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)

... and this is how it behaves in action:

>>> runEffect $ each ["Test", "ABC"] >-> example
Received value #0: "Test"
Received value #1: "ABC"
like image 78
Gabriella Gonzalez Avatar answered Oct 10 '22 01:10

Gabriella Gonzalez