2014-02-13 15 views
6

Ich habe eine Funktion mit einem Typ Map Int String -> Proxy() a() Void IO b. Gerade jetzt ist es await s, tut was auch immer mit dem Wert, den es bekam, und ruft sich dann wieder auf. Ich möchte es ändern, um State (Map Int String) zu verwenden, anstatt das als Argument übergeben zu haben, also kann ich einfach forever verwenden und muss nicht jeden Zweig erinnern, um recurse zu haben. Ich bekomme, dass ich StateT verwenden muss, um State mit einer anderen Monade zu kombinieren, aber ich verstehe nicht, wo in dieser Art Unterschrift die StateT gehört, oder ob ich oder lift Funktionen wie get muss. Was ist der richtige Typ für eine Funktion, die sowohl State (Map Int String) als auch Proxy() a() Void IO b ist?Wie funktioniert State mit Pipes?

+0

hoffe, das hilft! http://stackoverflow.com/questions/18471706/idiomatic-bidirectional-pipes-mit-downstream-state-without-loss – user3303858

Antwort

16

Hinweis: Proxy() a() Void = Consumer a, so werde ich es für diese Antwort als Consumer beziehen.

Die einfache Möglichkeit besteht darin, Ihre StateT Monade-Transformer-Schicht außerhalb der Consumer Schicht und dann sofort ausführen. Hier ein Beispiel:

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) 

... und das ist, wie es in Aktion verhält:

>>> runEffect $ each ["Test", "ABC"] >-> example 
Received value #0: "Test" 
Received value #1: "ABC"