Functional Banana Traveler — обработка ввода

Это подзадача моего проекта 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 правильным выбором?


person Michael Litchard    schedule 16.10.2012    source источник


Ответы (1)


Вы вероятно хотели

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

но я не проверял это. Кроме того, возможно, вы захотите избежать здесь tryReadTChan. Просто используйте старый добрый readTChan, чтобы получить эффективный retry вместо опроса.

person Daniel Wagner    schedule 16.10.2012