2013-06-30 12 views
7

Mam następujący program, który nie generuje żadnego wyjścia po uruchomieniu z runhaskell Toy.hs i zamiast tego zawiesza się na czas nieokreślony. Według mojego zrozumienia, program powinien wydrukować "cześć", a następnie wyjść. Byłbym wdzięczny za odpowiedź i/lub poradę, jak debugować taki problem. Używam Pipes 4.0.0 z github (github.com/Gabriel439/Haskell-Pipes-Library).Prosty program za pomocą potoków zawiesza się

module Toy where 

import Pipes 
import Control.Monad.State 

type Request = String 
type Response = String 

serveChoice :: Request -> Server Request Response IO() 
serveChoice = forever go 
    where go req = do 
     lift $ putStrLn req 
     respond req 

run :: Monad m =>() -> Client Request Response (StateT Int m)() 
run() = do 
    request "hi" 
    return() 

main :: IO() 
main = evalStateT (runEffect $ hoist lift . serveChoice >-> run $()) 0 

Odpowiedz

9

Trzeba użyć foreverK zamiast forever, tak:

module Toy where 

import Pipes 
import Pipes.Prelude (foreverK) 
import Control.Monad.State 

type Request = String 
type Response = String 

serveChoice :: Request -> Server Request Response IO() 
serveChoice = foreverK go 
    where go req = do 
     lift $ putStrLn req 
     respond req 

run :: Monad m =>() -> Client Request Response (StateT Int m)() 
run() = do 
    request "hi" 
    return() 

main :: IO() 
main = evalStateT (runEffect $ hoist lift . serveChoice >-> run $()) 0 

Powodem oryginalna wersja wisi jest to, że stosowane forever w Reader monady (tj ((->) a) monada), a nie monada rurowa. W ramach tej monady, forever jest równoważna :

-- i.e.  m b ->  m c 
forever :: (a -> b) -> (a -> c) 
forever m = m >> forever m 
      = m >>= \_ -> forever m 
      = \a -> (\_ -> forever m) (m a) a 
      = \a -> forever m a 
      = forever m 

foreverK jest chyba to, czego chciał, ponieważ jest to ten sam idiom dla Server s wprowadzonych w poradniku pipes-3.3.0.

Ta zmiana program, który naprawia teraz uzupełnia normalnie:

>>> main 
hi 
>>> 
+0

Skąd monada Reader przyjść na zdjęciu, jak nigdy nie powoływać go wyraźnie? Czy jest używany wewnętrznie w Pipes? – ajp

+4

@ajp To zachowanie nie jest w ogóle specyficzne dla rur. Kompilator określa, której monady użyć w kontekście, w którym nazywa się "na zawsze". Przez przypadek użyłeś 'forever go', gdzie kompilator oczekiwał funkcji typu' Request -> ', a nie potoku, więc kompilator wywnioskował, że monada miała na myśli' Request -> 'monad, a nie' Server Request Response ' Moneta IO, tak jak zamierzałeś. –