steveklabnik/frappuccino — pull request #11 by seadowg (2013-04-28 07:37:28+00:00)
Title: Return a Behaviour from Stream#count

This switches up returning an Integer from #count to it returning a Behaviour (FRP's time varying continuous value). We don't need the full Behaviour implementation for #count as we can just use the `stepper` function from the original FRP implementations (see [here](http://hackage.haskell.org/packages/archive/reactive/0.11.5/doc/html/src/FRP-Reactive-Behavior.html#stepper)).

### Stepper

Stepper takes an initial value and a Stream of new values. Basically, evaluating a Stepper at some point in time will return either the initial value (if the Stream is empty) or the last value that occurred on the stream (with respect to the current time). So:

stepper = Stepper.new(0, button.map { 1 })
stepper.now # => 0

button.push
stepper.now # => 1

I'm not sure how you feel about the naming here of both Stepper and the #now operation (that returns the value at the current time). I've heard this concept referred to as other things such as 'Signal' or 'Property' so that might be something to change.

### Scan

So we can return a Stepper that represents the count of a Stream I've added the #scan operation to Stream. This takes a zero value and a block and applies the block to the Stream in a similar way to reduce/inject but instead of returning a value it returns another Stream. This means it can operate on an infinite set.

To get a Stepper representing the count of a Stream we can just do this:

Stepper.new(0, stream.scan { |last, current| last + 1 })

One caveat with this implementation of #scan is that unlike other implementations (in Haskell or Scala for instance) it doesn't output the zero value as the first element of the result stream (it instead starts with the actual first result). This is mainly because I wasn't convinced by any way of 'pushing' this value. What would the 'time' of the occurrence be for the zero value for instance?

P.S. Where FRP gets really cool for me is that you wouldn't actually want to have people calling #now in their code: it would be hidden away in whatever they were interacting with. For instance, if we wanted to have some label in a GUI that would show the count of some event stream (and always be up to date) we could do:

Label.new(stream.count)

The idea would be that the GUI framework should take care of staying up to date and that the FRP framework just provides the ability to evaluate the Behaviour (and possibly some hooks for push based Behaviours like Stepper).