Open stevekrouse opened 5 years ago
While my intention was to continue my research in the direction of prototype 4, I have been tantilized by the problem of how to extend the FRP abstraction to "the backend". In other words, apps with data stored somewhere "in the cloud".
To extend the simple counter application, simply make it a multi-computer counter, that aggregates all the counts to a button across all computers. As is often the case, once put in those words, the problem doesn't seem so hard. One approach is to have a "lift" operator that would allow us to transform a button's Event ()
into a MultiWindow [Event ()]
, upon which we could do various operations, such as merging all the event streams and counting the occurrences.
Or consider the much more complicated problem of a realtime multiplayer game like agar.io or slither.io. As I've learned the hard way, you cannot simply send the x- and y- positions of each player to each other player and update position accordingly. You must instead anticipate where each player is going to be based on their current position and velocity and project them there until you receive the next word on their position and velocity and then you can subtly nudge that player to where they actually are, and are headed.
How could I model such an arrangement without mentioning low level details such as sockets? I think the concept of perspective is relevant here. From a single player's perspective the x- and y- position, and velocity are all FRP Behaviors, defined at all points in time because their computation happens to quickly. However, those values for other players must be modeled as FRP Events, because we only get glimpses of them at discrete points in time. However we must on the screen display other player's positions as continuous behaviors so we must use the complicated logic to predict and update our perception of the other players to construct a Behavior for them out of our Event of them.
My thinking above is lead by my intuition of FRP, types, and what the abstractions allow. However I feel a desperate need to have a proper medium to help shape my thoughts to only go in proper ways. Potentially Haskell or PureScript could be such a medium. I am considering watching/reading Conal's advice on denotative design again. Maybe I need to come up with mathematical objects to model what I mean by a "multi-widow" or "multi-user" application or event stream. These are the question on my mind when I pick up this stream of thoughts...
Conal Elliot is the man. My god, I'm so excited to be able to grok a part of what he has to say! Yesterday I re-watched Denotational Design: from meanings to programs and was re-blown away. It's funny: whenever I recommend Conal to friends I have to caveat it with, "I need to watch his stuff multiple times before I get it." This was true of this talk as well.
So here's the denotational methodology as far as I can tell:
So I tried to follow it in the shower yesterday and I think it went pretty well!
I had a few key insights:
Events a
on one computer to something like Event (Event User a)
, where the outer event represents this computer's perception of the event happening and the inner event represents when the event actually happened.user :: (public key, private key)
sign :: User -> Stream a -> UserStream a
the stream.lift
a Stream
to a Stream (Stream)
of some sort (to account for when we get the stream as well as when it happens), and in this lifting we can optionally supply a User
parameter. Pieces of state themselves will decide if and how they will allow themselves to be lifted, and to which users.Behavior
so that we can change this if we want to revoke access.Apache Beam shares some ideas with FRP, mainly that you build a graph based on data dependencies (denotational-style).
Thanks @tswast!
This issue is where I'm going to collect work and thoughts on the work for multi-node or cloud FRP. Below are a few "journal entries" that helped inform this work: