Functional Banana Traveler - A Combination of Behavior t GameState

The problem is that I don’t know how to create behavior like Behavior t GameState

I have more code, but I'm trying to just show that, in my opinion, it is necessary to talk about the problem. Let me know if there are spaces to fill. Here is 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 network of events

 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 ran into a type problem

 stepper :: a -> Event ta -> Behavior ta 

This makes me think that I need to convert eInput :: Event t PlayerCommand to eGameState :: Event t GameState , which I can use with stepper to make Behavior t GameState

So My questions, is my line of thinking correct? If not, can I be redirected? If so, what would eGameState :: Event t GameState look like?

In response to the answer below. When I first looked at accumB , I saw a type error when creating. This is what happened when I tried your suggestion.

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

gives an 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 with it. I will look at your examples and see if the answer becomes clear. Thanks for choosing accumB right way since I focused on stepper

The more I study the proposed code, the more I get puzzled by a type error.

+2
source share
1 answer

In fact, you need to create an event that remembers GameState and applies the updateGS function to it to create a new one. This is the purpose of the accumE function and its cousin accumB . In particular, you can write

 bGameState = accumB initialGS $ updateGS <$> eInput 

To learn more about this template, check out the examples on the sample pages , specifically the Counter.hs and TwoCounters.hs examples.


Another point worth mentioning is that I recommend avoiding the changes function if you are not dealing with low-level frameworks. As noted in the documentation, it has several limitations; the most nasty limitation is that the value is not available until reactimate is executed. You can easily make an endless loop this way; its purpose is really very narrow.

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

Moral: turning an event into behavior is easy, but there is no turning back.

+2
source

Source: https://habr.com/ru/post/1442138/


All Articles