2013-06-30 32 views
7

我有以下程序,它在與runhaskell Toy.hs一起運行時不產生輸出,而是無限期地掛起。據我瞭解,該程序應打印「嗨」,然後退出。我將不勝感激關於如何調試此類問題的答案和/或建議。我在github上使用Pipes 4.0.0(github.com/Gabriel439/Haskell-Pipes-Library)。使用管道的簡單程序掛起

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 

回答

9

您需要使用foreverK代替forever,像這樣:

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 

您的原始版本掛起的原因是,您在Reader單子使用forever(即((->) a)單子),而不是管單子。在這個單子,forever相當於

-- 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可能是你想要的東西,因爲它是在pipes-3.3.0教程中介紹Server S也是一樣的成語。

這一變動修正程序現在正常完成:

>>> main 
hi 
>>> 
+0

哪裏讀者單子進入畫面,因爲我從來沒有調用它明確?它是否在管道內部使用? – ajp

+4

@ajp這種行爲根本不是「管道」特有的。編譯器推斷在你稱之爲「forever」的上下文中使用哪個monad。你不小心使用了'forever go',因爲編譯器希望得到一個'Request - >'類型的函數,而不是一個管道,所以編譯器推斷出你指的monad是'Request - >'monad而不是'Server Request Response IO'單子像你想的那樣。 –