2015-12-13 8 views
8

Ho una piccola Haskell Pipe che stampa quante volte ha eseguito:Come rilevare l'ultimo blocco in una pipe Haskell?

counterPipe :: Pipe String String IO r 
counterPipe = go 0 
    where 
    go n = do 
     await >>= yield 
     let n' = succ n 
     liftIO $ putStrLn $ "Chunk " ++ show n' 
     go n' 

mi piacerebbe essere in grado di stampare un messaggio, e potenzialmente eseguire altre attività, una volta che ha elaborato l'ultima pezzo. Come procedo a fare questo?

risposta

3

ho potuto farlo funzionare modificando counterPipe 's tipo di ingresso per Maybe String e iniettare un extra Nothing dopo la fine del tubo a monte:

import Pipes 
import Pipes.Core (respond) 
import Control.Applicative ((<*)) 

withEOF :: (Monad m) => Proxy a' a b' b m r -> Proxy a' a b' (Maybe b) m r 
withEOF p = for p (respond . Just) <* respond Nothing 

counterPipe :: Pipe (Maybe String) String IO Int 
counterPipe = go 0 
    where 
    go n = do 
     mx <- await 

     case mx of 
      Just x -> do 
       yield x 
       let n' = succ n 
       liftIO $ putStrLn $ "Chunk " ++ show n' 
       go n' 
      Nothing -> do 
       return n 

finishCounter :: Int -> Pipe a b IO() 
finishCounter n = liftIO $ putStrLn $ unwords ["Finished after", show n, "chunks"] 

Esempio conducente:

import qualified Pipes.Prelude as P 
main = runEffect $ withEOF P.stdinLn >-> (counterPipe >>= finishCounter) >-> P.stdoutLn 

I pensare che questo modello dovrebbe essere abstractable in qualcosa come

whileJust :: (Monad m) => Proxy a' a b' b m r -> Proxy a' (Maybe a) b' b m (Maybe r) 

così si potrebbe scrivere

withEOF P.stdinLn >-> (whileJust counterPipe >>= maybe (return()) finishCounter) >-> P.stdoutLn 

senza dover cambiare il vostro counterPipe definizione originale; ma non ho mai usato prima Pipes (la soluzione di cui sopra è stata pensata guardando solo i tipi e giocando a domino tipo) e quindi non sono riuscito a scrivere whileJust (la firma è probabilmente troppo generica in modi che non posso risolvere).