功能性的香蕉旅行者 - 放在一起行为t GameState [英] Functional Banana Traveller - putting together Behavior 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
,我可以在步进器中使用
使
所以,我的问题是,我的思路是否正确?如果不是,我可以重新定向吗?如果是这样, 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
的事件并将 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屋!