2015-12-13 9 views
8

Mam mały Haskell Pipe że wypisuje ile razy to run:Jak wykryć ostatni fragment w rurze Haskella?

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' 

Chciałbym, aby móc wydrukować wiadomość, a potencjalnie wykonywać inne zadania, po ich przetworzeniu ostatniego kawałek. Jak mam to zrobić?

Odpowiedz

3

udało mi się uzyskać to do pracy poprzez zmianę counterPipe „s typ wejścia do Maybe String i wstrzyknięcie dodatkowej Nothing po upstream wykończeń rury:

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"] 

Przykład Kierowca:

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

I sądzę, że ten wzorzec powinien być abstrakcyjny w coś takiego, jak

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

więc można napisać

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

bez konieczności zmiany oryginalnej counterPipe definicji; , ale nigdy wcześniej nie korzystałem z Pipes (powyższe rozwiązanie zostało opracowane po prostu patrząc na typy i typ gry - domino), więc nie udało mi się napisać whileJust (podpis jest prawdopodobnie zbyt ogólny w sposób, w jaki nie mogę rozwiązać).