Функциональный Banana Traveler - Обработка ввода
Это подзадача из моего проекта Traveler.
Я собрал рудиментарный код, который будет обрабатывать ввод. Это работает, пока я не представлю 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
правильный выбор?
1 ответ
Вы, вероятно, хотели
forkIO $ forever (atomically (tryReadTChan commandChannel) >>= fireCommand)
но я не проверял это. Кроме того, по-видимому, вы, вероятно, захотите избежать tryReadTChan
Вот. Просто используйте старый добрый readTChan
, так что вы получите эффективный retry
вместо опроса.