2012-10-16 21 views
0

這是來自我的Traveller項目的子問題。功能性香蕉旅行者 - 輸入處理

我已經放在一起處理輸入的粗魯的代碼。它的工作原理,直到我引入TChan的混合。以下是工作代碼,並舉例說明如何使用它。然後,我會改變它並解釋我爲什麼這樣做。然後,我會談論這個問題。

{-# LANGUAGE ScopedTypeVariables #-} 
import Control.Monad (forever) 
import Control.Concurrent (forkIO) 
import Control.Monad.STM (STM,atomically) 
import Control.Concurrent.STM.TChan 
import Reactive.Banana 
import Reactive.Banana.Frameworks 


data Planet = Vulcan 
      | Mars 
      | Terra 
       deriving (Eq,Read,Show) 

data Command = Move Planet 
      | Look 
      | Quit 
      | Null 
       deriving Show 

makeNetworkDescription :: AddHandler (Maybe Command) -> IO EventNetwork 
makeNetworkDescription addCommandEvent = compile $ do 
    eInput <- fromAddHandler addCommandEvent 
    let eCommand = filterJust eInput 
     bCommand = stepper Null eCommand 
    eCommandChanged <- changes bCommand 

reactimate $ (\n -> appendFile "output.txt" ("Command is " ++ show n)) <$> 
eCommandChanged 

ghci中執行以下操作將證明此方法有效。

(addCommandEvent,fireCommand) <- newAddHandler :: IO (AddHandler (Maybe Command),Maybe Command -> IO()) 
networkDescr <- makeNetworkDescription addCommandEvent 
actuate networkDescr 
return (Just $ Look) >>= fireCommand 

所以,現在我已經有了基本的機制,我想開始構建它。這將是一個多人遊戲。處理輸入的第一步是從TChan獲取輸入。這個想法是,所有玩家將寫入這個TChan,並且每個命令將按其到達的順序進行處理。

所以我增加了一個新功能「inputFrame」

inputFrame :: TChan Command -> IO() 
inputFrame commandChannel = do 
    (addCommandEvent,fireCommand) <- newAddHandler 
    networkDescr <- makeNetworkDescription addCommandEvent 
    actuate networkDescr 
    forkIO $ forever (atomically $ tryReadTChan commandChannel) >>= fireCommand 
    return() 

這裏是我嘗試使用它,在ghci

commandChan <- atomically $ newTChan :: IO (TChan Command) 
_ <- atomically $ writeTChan commandChan Look 

output.txt沒有被寫入。 commandChan正在讀取,因爲我檢查填充它後是否變空。這顯然是我做錯了嗎?如果沒有,我該如何解決這個問題呢?另外,對於我的預期目的,TChan是正確的選擇?

回答

2

可能

forkIO $ forever (atomically (tryReadTChan commandChannel) >>= fireCommand) 

,但我沒有測試過這一點。另外,猜測,你可能會想在這裏避免tryReadTChan。只需使用普通的老式readTChan,這樣您就可以獲得高效的retry而不是輪詢。