功能性香蕉旅行者 - 输入处理 [英] Functional Banana Traveller - Input Handling
问题描述
这是我的 Traveler 项目的一个子问题。
我已经将处理输入的粗糙代码放在一起。它的工作原理,直到我介绍 TChan
混合。以下是工作代码,并举例说明如何使用它。然后,我会改变它并解释我为什么这样做。然后,我会讨论这个问题。
{ - #LANGUAGE ScopedTypeVariables# - }
import Control.Monad (永久)
导入Control.Concurrent(forkIO)
导入Control.Monad.STM(STM,原子地)
导入Control.Concurrent.STM.TChan
导入Reactive.Banana
import Reactive.Banana.Frameworks
data Planet = Vulcan
| Mars
| Terra
导出(Eq,Read,Show)
数据命令=移动星球
|看看
|退出
|无
派生显示
makeNetworkDescription :: AddHandler(也许命令) - > IO EventNetwork
makeNetworkDescription addCommandEvent =编译$ do
eInput< - fromAddHandler addCommandEvent
let eCommand = filterJust eInput
bCommand = stepper Null eCommand
eCommandChanged< - changes bCommand
reactimate $(\\\
- > appendFileoutput.txt(Command is++ show n))< $>
eCommandChanged
执行 ghci $ c $ (AddCommandEvent,fireCommand)< - newAddHandler :: IO(AddHandler(也许命令))将会显示这是有效的。
,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
执行networkDescr
forkIO $ forever tryReadTChan commandChannel)>> = fireCommand
return()
在 ghci
中使用它。
commandChan< - atomically $ newTChan :: IO(TChan Command)
_< - 原子地$ writeTChan commandChan Look
output.txt
不会被写入。正在读取 commandChan
,因为我在填充它后检查它是否为空。这显然是我做错了吗?如果没有,我该如何解决这个问题呢?此外,对于我的预期目的,
< (原子性)(tryReadTChan commandChannel)>> =您可能需要 fireCommand)
但我没有测试过这个。此外,在猜测,你可能会想在这里避免 tryReadTChan
。只需使用普通的 readTChan
,这样你就可以获得高效的重试
而不是轮询。
This is a sub-problem from my Traveller project.
I've put together the rudementary code that will handle input. It works, until I introduce a TChan
to the mix. Below is the working code, with an example of how to use it. Then, I will change it and explain why I am doing so. Then, I'll talk about the problem.
{-# 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
Executing the following in ghci
will demonstrate that this works.
(addCommandEvent,fireCommand) <- newAddHandler :: IO (AddHandler (Maybe Command),Maybe Command -> IO ())
networkDescr <- makeNetworkDescription addCommandEvent
actuate networkDescr
return (Just $ Look) >>= fireCommand
So, now I have have the basic mechanism in place, I want to start building it out. This is going to be a multiplayer game. The first step in addressing this as far the the input handling goes is getting input from a TChan
. The idea being, all players will write to this TChan
, and each command will be processed in the order it arrived.
So I added a new function 'inputFrame'
inputFrame :: TChan Command -> IO ()
inputFrame commandChannel = do
(addCommandEvent,fireCommand) <- newAddHandler
networkDescr <- makeNetworkDescription addCommandEvent
actuate networkDescr
forkIO $ forever (atomically $ tryReadTChan commandChannel) >>= fireCommand
return ()
Here is how I attempt to use it, in ghci
.
commandChan <- atomically $ newTChan :: IO (TChan Command)
_ <- atomically $ writeTChan commandChan Look
output.txt
doesn't get written to. commandChan
is being read, as I check to see if it becomes empty after populating it. Is it obvious what I'm doing wrong? If not, how may I go about troubleshooting the problem? Also, for my intended purposes, is a TChan
the right choice?
You probably wanted
forkIO $ forever (atomically (tryReadTChan commandChannel) >>= fireCommand)
but I haven't tested this. Also, at a guess, you probably will want to avoid tryReadTChan
here. Just use plain old readTChan
, so that you get the efficient retry
instead of polling.
这篇关于功能性香蕉旅行者 - 输入处理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!