2013-05-08 129 views
5

有沒有什麼東西與liftIO相反?我使用的是websockets,我希望能夠在單獨的線程中監聽來自服務器的消息。下面是我在做什麼:在IO monad中使用monad

import Network.WebSockets 
import qualified Data.Text as T 
import Control.Monad.IO.Class 
import Control.Monad 
import Control.Concurrent 
import Control.Applicative 

printMessages :: WebSockets Hybi00() 
printMessages = forever $ do 
    resp <- receiveDataMessage 
    liftIO $ print resp 

run :: WebSockets Hybi00() 
run = do 
    liftIO . forkIO $ printMessages 
    forever $ do 
     line <- liftIO getLine 
     sendTextData . T.pack $ line 

main = connect "0.0.0.0" 8080 "/" run 

所以printMessages偵聽來自服務器的消息,並不停打印出來。問題是,forkIO需要返回IO()的函數。有什麼辦法可以讓我在IO monad中運行printMessages

+1

['runWithSocket'](http://hackage.haskell.org/packages/archive/websockets/latest/doc/html/ Network-WebSockets.html#v:runWithSocket)或許?一般來說,爲了從'MonadIO m'到'IO',你需要一些'runXY'函數。 – 2013-05-08 21:57:15

回答

5

如果我理解這個權利,你想在另一個線程中接收消息的原因是因爲主線程將等待用戶輸入發送。

the documentation的角度來看,如果您反轉線程的角色,您似乎有更輕鬆的時間:在主線程中接收,並從另一個線程異步發送。

然後你可以使用getSink :: Protocol p => WebSockets p (Sink p)在分叉之前抓住一個水槽,然後你可以使用sendSink :: Sink p -> Message p -> IO(),它住在IO,避免混合單體的整個問題。

換句話說,調整你的代碼是這樣的:

sendMessages :: Sink Hybi00 -> IO() 
sendMessages sink = forever $ do 
    line <- getLine 
    let msg = textData . T.pack $ line 
    sendSink sink msg 

run :: WebSockets Hybi00() 
run = do 
    sink <- getSink 
    liftIO . forkIO $ sendMessages sink 
    forever $ do 
     resp <- receiveDataMessage 
     liftIO $ print resp 

main = connect "0.0.0.0" 8080 "/" run 
+1

謝謝!我修改了你的答案以添加我的工作代碼。 – 2013-05-08 23:31:18