[Haskell-cafe] Observer pattern in haskell FRP

Heinrich Apfelmus apfelmus at quantentunnel.de
Thu Nov 29 18:28:08 CET 2012


Nathan Hüsken wrote:
> Heinrich Apfelmus wrote:
>>
>> Personally, I would recommend is a complete change in perspective.
>>
>> The main idea of FRP is that it is a method to describe the evolution of
>> values in time. What is a game? It's just a picture that evolves in
>> time. The user can exert influence on the evolution by clicking certain
>> buttons on a mechanical device, but in the end, all he sees is a picture
>> that moves. [..]
> 
> That perspective certainly make sense. But couldn't one also describe a
> game as a set of entities (spaceships) that react to the clicking of
> buttons?

Of course, generally speaking, you can describe it any way you like, FRP 
is just a perspective, not a dictatorial doctrine.

But you probably mean that you want to describe spaceships within the 
FRP perspective, though independent of how they are displayed. That's a 
good point, which I missed. (The guideline of working backwards from the 
very final result has served me very well when developing in FRP style, 
though, hence my insistence on it.)

In the FRP perspective, I would use a slightly different language, 
though. Namely, I would not say that spaceships are "entities that react 
to button clicks", but rather that they are "represented by time-varying 
positions that depend on past button clicks". The change is subtle but 
important: you invert the direction of control. Instead of having a 
button click do something to the spaceship ("push"), you have a 
spaceship whose present position depends on past button clicks ("pull").

The FRP perspective is also more "holistic": you can think of a 
spaceship and other time-varying values as if you knew their values for 
all points in time, as if you were given graphical plots. (I have drawn 
a few pretty pictures in the slides linked to here 
<http://apfelmus.nfshost.com/blog/2012/07/15-frp-tutorial-slides.html>)

> If I take for example the breakout game from here [1]. It outputs an
> object "scene" of type Picture. But this picture is calculated from the
> objects "ballPos" and "paddlePos". So first a game state (ballPos,
> paddlePos) is created and than transformed to something renderable.
> 
> I believe all examples I have seen for games with FRP follow this
> pattern, and I would I want to do is seperate the steps of calculating
> the game state and calculating the renderable from it.

In that light, the separation seems straightforward to me. Given the 
time-varying values that represent game objects,

    bSpaceShipPosition :: Behavior Position
    bAsteroidPositions :: Behavior [Position]
    bTime              :: Behavior Time

you can transform and combine them into a graphic, for instance like this

    bSpaceShipPicture :: Behavior Graphic
    bSpaceShipPicture =
        blinkenLights <$> bTime <*> bSpaceShipPosition

    bAsteroidPictures = map drawAsteroid <$> bAsteroidPositions

    bPicture = overlay <$>
        ((:) <$> bSpaceShipPicture <*> bAsteroidPictures)

In other words, you just combine old time-varying values into new ones, 
much like you would combine combine graphical plots. Also note that you 
can add animation a posteriori; it doesn't have to be part of the values 
representing a space ship.


Of course, one important question is whether to represent asteroid 
positions as a time-varying collection  Behavior [Position]  or as a 
collection of time-varying values  [Behavior Position] . The latter form 
tends to require dynamic event switching, while the former form tends 
towards a monolithic  GameState  value, which would forgo many of the 
advantages of FRP.

I don't have enough practical experience to give a useful recommendation 
here, but at the moment, I tend towards breaking it up as much as 
possible, but trying to avoid dynamic event switching. My rule of thumb 
is to model similar objects (asteroids) as a time-varying collection, 
while modeling distinct objects (player space ship) as individual behaviors.


Best regards,
Heinrich Apfelmus

--
http://apfelmus.nfshost.com




More information about the Haskell-Cafe mailing list