功能性香蕉旅行者 - 输入处理 [英] Functional Banana Traveller - Input Handling

查看:178
本文介绍了功能性香蕉旅行者 - 输入处理的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的 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

  ,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 ,因为我在填充它后检查它是否为空。这显然是我做错了吗?如果没有,我该如何解决这个问题呢?此外,对于我的预期目的, TChan 是正确的选择吗?

解决方案

< (原子性)(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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆