Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How should FRP work at the top level?

I have been experimenting with creating a Functional Reactive Programming framework for Scala. One thing at the moment I am confused about is how current implementations have dealt with representing behaviours at the top level. To explain what I mean I'll give an example. Say I have a JPanel and I want to do this:

 JPanel panel = new Panel()
 panel.setBackground(new Behaviour(time => Color.red))

Although the color is static here we want the panel background to update when the value of the Behaviour updates. The way I have done it so far is to essentially create a discretized Behaviour using Events (accessible via a changes function on Behaviours). This is basically just an event source that occurs whenever the Behaviour changes. Using this the implementation of setBackground here would be:

def setBackground(color : Behaviour[Color]) {
  super.setBackground(color.now)
  color.changes.each(change => super.setBackground(change))
}

This feels kind of messy. Does anyone have any suggestions of whether this is a bad approach or not? I have been looking at Elliott's Push-Pull FRP today and it feels like I might be going in the right direction but getting lost somewhere.

EDIT: If no one has a definite clear cut solution then ideas/thoughts would be great!

like image 525
seadowg Avatar asked Oct 14 '11 17:10

seadowg


1 Answers

Two things:

  1. In Conal Elliott's original vision, behaviors are continuous in time, so they don't come with a function changes that indicates when they change.

    The behavior that returns the current clock time would be the prime example of a continuous behavior. It doesn't support a changes function, unless you specify a time step ("it generates a 'change' event every nanosecond"). But the point of "continuous" is the lack of a time step.

    In my view, this means that behaviors in Conal's sense don't support incremental updates at all. In my reactive-banana library, I have introduced a new data type Discrete that is some kind of hybrid between behaviors and events. See the documentation of the module Reactive.Banana.Incremental for more details on the rationale.

  2. You are probably annoyed by having wrap each and every GUI function like setBackground to make it work with behaviors instead of plain values. This is were higher-order functions really shine: the wrapper is always the same, you can express it as a higher order function; here a Haskell version:

    set' :: Property a -> Behavior a -> IO ()
    set' property behavior = do
         set property (now behavior)
         each (\a -> set property a) (changes behavior)          
    
    each f event = reactimate (fmap f event) -- helper definition
    
    example = set' background red
    

    Of course, this relies a lot on Haskell's syntax and may not be as pleasant in Scala, where some functions are written before their first argument.

like image 123
Heinrich Apfelmus Avatar answered Nov 06 '22 06:11

Heinrich Apfelmus