功能性的香蕉旅行者 - 放在一起行为t GameState [英] Functional Banana Traveller - putting together Behavior t GameState

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

问题描述

问题是我不知道如何创建类型的行为行为t GameState



I有更多的代码,但我试图只显示我认为有必要谈论这个问题。

 数据GameState = GameState {agent :: Agent 
,universe :: Universe
}

类型Universe = Gr Planet()

data Command =移动PlanetName
|看看
|退出
导出显示

数据PlayerCommand = PlayerCommand命令PID
|无
派生显示

updateGS :: PlayerCommand - > GameState - > GameState
updateGS(PlayerCommand(Move planet)pid)gs =
let agent = getAgent pid gs
nodes = labNodes $ universe gs
current = location agent
Just fromP = lookup(fromEnum current)节点
只需要toP = lookup(fromEnum planet)节点
fromNode = fromEnum current
toNode = fromEnum planet
uPlayer = Player pid(getPlanetName toP)(Location星球)
mData = MoveData uPlayer(toNode,toP)(fromNode,fromP)节点
uPlanets = updateLNodeList mData
在GameState uPlayer(mkGraph uPlanets $ labUEdges gates

initialGS :: GameState
initialGS = GameState initPlayer(makeUniverse makePlanetNodes)

和事件网络

  makeNetworkDescription :: AddHandler PlayerCommand  - > IO EventNetwork 
makeNetworkDescription addCommandEvent = compile $ do
eInput< - fromAddHandler addCommandEvent
让bCommand = stepper Null eInput
eCommandChanged< - changes bCommand
let bGameState :: Behavior t GameState
bGameState = stepper initialGS
reactimate $(\\\
- > appendFileoutput.txt(Command is++ show n))< $> eCommandChanged

我相信bGameState需要使用eCommandChange,但遇到类型问题

  stepper :: a  - >事件t a  - >行为ta 

这让我相信我需要转换 eInput :: Event t PlayerCommand 转换为
eGameState :: Event t GameState ,我可以在步进器中使用使行为t GameState



所以,我的问题是,我的思路是否正确?如果不是,我可以重新定向吗?如果是这样, eGameState :: Event t GameState 看起来像什么?



回应以下回应。当我最初考虑 accumB 时,我看到了一个类型错误。

  let bGameState ::行为t GameState 
bGameState = accumB initialGS $ updateGS <$ eInput

产生错误

 无法匹配预期类型`GameState'
,实际类型为`PlayerCommand'
期望类型:GameState - > GameState
实际类型:PlayerCommand - > GameState - > GameState $ b $在'(< $)'的第一个参数中,即`updateGS'
在`($)'的第二个参数中,即`updateGS <$ eInput'

不知道该怎么做。我会看看你的例子,看看答案是否清晰。感谢您提供 accumB 是正确的选择,因为我专注于步进器



我研究建议的代码越多,我越是被类型错误困惑。

事实上,您需要创建一个记录 GameState 的事件并将 updateGS 函数应用于该事件以创建一个新的一个。这就是函数 accumE 及其表弟 accumB 的用途。特别是,你可以写下:

  bGameState = accumB initialGS $ updateGS< $> eInput 

要了解有关此模式的更多信息,请查看示例页面,特别是Counter.hs和TwoCounters.hs示例。






另一点值得一提的是,我建议避免更改函数,除非您正在处理低级框架的东西。正如文件中指出的那样,它有几个限制;最棘手的限制是该值在 reactimate 执行之前不可用。你可以很容易地做出一个无限循环,其目的非常狭窄。



在你的情况下, bCommand 看起来多余,你有 eCommandChanged = eInput



士气:将事件转化为行为很容易,但没有回头路。


The problem is that I do not know how to create the Behavior of type Behavior t GameState

I have more code, but am trying to just show what I think is neccessary to talk about the problem. Let me know if there are blanks to be filled in. Here's what I have :

data GameState = GameState {agent    :: Agent
                           ,universe :: Universe
                           }

type Universe = Gr Planet ()

data Command = Move PlanetName
             | Look
             | Quit
                 deriving Show

data PlayerCommand = PlayerCommand Command PID
                   | Null
                       deriving Show

updateGS :: PlayerCommand -> GameState -> GameState
updateGS (PlayerCommand (Move planet) pid) gs =
   let agent = getAgent pid gs
       nodes = labNodes $ universe gs
       current = location agent
       Just fromP = lookup (fromEnum current) nodes
       Just toP   = lookup (fromEnum planet) nodes
       fromNode = fromEnum current
       toNode = fromEnum planet
       uPlayer = Player pid (getPlanetName toP) (Location planet)
       mData = MoveData uPlayer (toNode,toP) (fromNode,fromP) nodes
       uPlanets = updateLNodeList mData
   in GameState uPlayer (mkGraph uPlanets $ labUEdges gates

initialGS :: GameState
initialGS = GameState initPlayer (makeUniverse makePlanetNodes)

and the event network

makeNetworkDescription :: AddHandler PlayerCommand -> IO EventNetwork
makeNetworkDescription addCommandEvent = compile $ do
   eInput <- fromAddHandler addCommandEvent
   let bCommand = stepper Null eInput
   eCommandChanged <- changes bCommand
   let bGameState :: Behavior t GameState
       bGameState = stepper initialGS 
   reactimate $ (\n -> appendFile "output.txt" ("Command is " ++ show n)) <$> eCommandChanged

I believe bGameState needs to use eCommandChange, but I run into a problem with the types

stepper :: a -> Event t a -> Behavior t a

this leads me to believe I need to transform eInput :: Event t PlayerCommand into a eGameState :: Event t GameState, which I can use with stepper to make the Behavior t GameState

So, My questions are, is my line of thinking correct? If not, could I be re-directed? If so, what would eGameState :: Event t GameState look like?

In response to the response below. When I considered accumB initially, I saw a type error in the making. Which is what happened when I tried your suggestion.

let bGameState :: Behavior t GameState
    bGameState = accumB initialGS $ updateGS <$ eInput

yields the error

 Couldn't match expected type `GameState'
             with actual type `PlayerCommand'
 Expected type: GameState -> GameState
   Actual type: PlayerCommand -> GameState -> GameState
 In the first argument of `(<$)', namely `updateGS'
 In the second argument of `($)', namely `updateGS <$ eInput'

Not sure what to do about that. I'll look at your examples and see if the answer becomes clear. Thanks for poiting out accumB was the right way to go, as I was focused on stepper

The more I study the suggested code, the more I am puzzled by the type error.

解决方案

Indeed, you need to create an event which remembers a GameState and applies the updateGS function to it to create a new one. That's the purpose of the function accumE and its cousin accumB. In particular, you can write

bGameState = accumB initialGS $ updateGS <$> eInput

To learn more about this pattern, have a look at the examples on the examples pages, in particular the Counter.hs and TwoCounters.hs examples.


Another point worth mentioning is that I recommend to avoid the changes function unless you are dealing with low-level framework stuff. As noted in the documentation, it has several restrictions; the nastiest restriction being that the value is not available until the reactimate are executed. You can easily make an infinite loop that way, its purpose is really very narrow.

In your case, the bCommand seems superfluous anyway, you have eCommandChanged = eInput.

Morale: Turning an event into a behavior is easy, but there is no way back.

这篇关于功能性的香蕉旅行者 - 放在一起行为t GameState的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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