Re: [Haskell-cafe] Is this a correct explanation of FRP?

2012-04-02 Thread Peter Minten
On Mon, 2012-04-02 at 04:03 +0200, Ertugrul Söylemez wrote:
 Peter Minten peter.min...@orange.nl wrote:
  As I see FRP it has three components: the basic concepts, the
  underlying theory and the way the libraries actually work.
 
  As far as I understand FRP (which is not very far at all) the basic
  concepts can, simplified, be formulated as:
 
  * There are things which have a different value depending on when you
  look at them. (behaviors)
 
 That's already specific to traditional FRP.  In AFRP the value mutates.
 It's not a function of some notion of time.  It is similar to a list.
 That list contains the current value as well as a description of the
 future of the value:
 
 newtype SF a b = SF (a - (b, SF a b))
 
 The current value and the future depend on a momentary input value of
 type 'a' (which usually comes from another SF).

I think I understand what you're saying now. Basically instead of
behaviors netwire has signal functions which are basically the same idea
as simplified conduits/enumeratees. When you step (run) a signal
function you get two things: an output value and a replacement for the
signal function. Because the signal functions can be replaced a system
of signal functions can change between steps.

Netwire doesn't actually have a notion of time as such. If you need to
know the current time you'll have to supply that yourself. Wires also
don't run continuously, only when stepped explicitly. Where in
traditional FRP you (in some libraries) could ask for the value of a
behavior at any time in netwire you can only get the equivalent value
(the output value of a signal function) by stepping.

The big difference between netwire and traditional AFRP libraries are
ArrowChoice instances which allow if-then-else and case constructions in
proc notation. This simplifies programming greatly as it requires less
thinking in FRP terms.

When you say Event a b = SF a (Maybe b) you're basically saying that
for netwire events are the same thing as behaviors: they're both signal
functions. Events can be expressed as signal functions that sometimes
have a value. If they have a value during a step the event occurs during
that step.

The whole system is very discrete, time isn't a primitive at all. If
time plays a role it's just as an input, it's not built into something.
To get something return 1 but from second 10 onward return 2 you pass
time as an input and once you see that the time is greater than 10 you
can change the signal function to arr (const 2) to fix it to return 2,
whatever the new time is.

Greetings,

Peter Minten


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Is this a correct explanation of FRP?

2012-04-01 Thread Peter Minten
On Fri, 2012-03-30 at 02:30 +0200, Ertugrul Söylemez wrote:
 Peter Minten peter.min...@orange.nl wrote:
 
  I've been trying to get my head around Functional Reactive Programming
  by writing a basic explanation of it, following the logic that
  explaining something is the best way to understand it.
 
  Am I on the right track with this explanation?
 
 You are explaining a particular instance of FRP.  Functional reactive
 programming is not a single concept, but a whole family of them.
 Traditional FRP as implemented by reactive-banana (and older libraries
 like Elerea, Fran and Reactive) is based on behaviors and events.  It
 uses the notion of a time-dependent value in a direct fashion.
 Conceptionally traditional FRP is this:
 
 Behavior a = Time - a
 Event a= [(Time, a)]
 
 -- The current time at even seconds and half the current time at odd
 -- seconds:
 
 alterTime = fullTime
 fullTime = switch (after 1) currentTime halfTime
 halfTime = switch (after 1) (fmap (/ 2) currentTime) fullTime
 
 There is a second instance of FRP though called AFRP.  The A stands for
 arrowized, but in modern times I prefer to think of it as
 applicative.  The underlying control structure is now a category and
 the concept of a time-varying value is changed to a time-varying
 function (called signal function (SF)), which is just an automaton and
 there is an arrow for it.  This simplifies implementation, makes code
 more flexible and performance more predictable.  The libraries Animas
 and Yampa implement this concept (Animas is a fork of Yampa).
 Conceptionally:
 
 SF a b= a - (b, SF a b)
 Event a b = SF a (Maybe b)
 
 alterTime = fullTime
 fullTime = switch (after 1) currentTime halfTime
 halfTime = switch (after 1) ((/ 2) ^ currentTime) fullTime

Sorry, I don't understand this. Would it be correct to say that AFRP
shares the basic ideas of FRP in that it has behaviors and
events/signals and that the main difference comes from the way AFRP is
implemented?

As I see FRP it has three components: the basic concepts, the underlying
theory and the way the libraries actually work.

As far as I understand FRP (which is not very far at all) the basic
concepts can, simplified, be formulated as:

* There are things which have a different value depending on when you
look at them. (behaviors)
* It is possible to express that something has occured at a certain
point in time. (events/signals)
* Behaviors can change in response to events/signals.
* A behavior's value may be different on different points in time even
if no event has come in.

Normal FRP theory expresses behaviors as Time - a and events as
[(Time,a)]. AFRP uses some kind of signal function to express
behaviors, or behaviors are signal functions and those functions
interact with events. Anyway AFRP uses a completely different
theoretical way of thinking about events and behaviors.

The reactive-banana library uses some internal representation which
exposes an API using applicative functors. The theory behind it, as
shown in the haddock comments, is Normal FRP.

The reactive library uses monads and not just applicative functors. It
uses the Normal FRP style.

Yampa/Animas use arrows and have a different underpinning in math.
However the basic concepts of FRP are shared with all the other
libraries.

Netwire also uses AFRP but extends the theory with something called
signal inhibition. Like everything else it shares the basic concepts of
FRP.

FRP concepts - FRP- reactive
   - reactive-banana
 - AFRP   - Yampa
   - Animas
 - wired AFRP - Netwire

Is this a correct way to summarize the differences?

Greetings,

Peter Minten


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Is this a correct explanation of FRP?

2012-03-31 Thread Peter Minten
On Fri, 2012-03-30 at 09:15 +0300, Michael Snoyman wrote:

 First you state that we shouldn't use `union` for the `ePitch` Event,
 and then you used it for `bOctave`. Would it be more efficient to
 implement bOctave as someting like:
 
 eOctave :: Event t (Int - Int)
 eOctave =
 filterJust toStep $ eKey
   where
 toStep '+' = Just (+ 1)
 toStep '-' = Just (subtract 1)
 toStep _ = Nothing
 
 bOctave :: Behavior t Octave
 bOctave = accumB 0 eOctave

Yes. Though it's slightly less bad, the case with ePitch was something
like 6 appends. It was mostly a case of badly copying the style from the
examples and not realizing the examples use event streams from different
outside sources. I've adapted the example to use something similar to
your eOctave.

 Also, I'm left wondering: how would you create a new event stream in
 the first place? You're telling us to just rely on `eKey`, which is
 fair, but a great follow-up would demonstrate building it. Looking
 through the docs I found `newEvent`, but I'm not quite certain how I
 would combine it all together.

The updated document, which now lives at
http://www.haskell.org/haskellwiki/FRP_explanation_using_reactive-banana
contains a Making the example runnable section which shows how connect
the example with the outside world.

The short version, regarding the creation of new events, is that you
have to do it in two parts. You need newAddHandler in the IO monad to
get a (a - IO ()) function that fires the event as well as something
called an AddHandler and fromAddHandler in the NetworkDescription monad
to get an event from that AddHandler. It's not possible to get values
out of the NetworkDescription monad (without IORef tricks) and events
can only be created within a NetworkDescription monad.

The newEvent function looks like what you'd want, but because you can't
get the event firing function out of NetworkDescription its use is
limited.

Greetings,

Peter Minten


___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


[Haskell-cafe] Is this a correct explanation of FRP?

2012-03-29 Thread Peter Minten
Hi,

I've been trying to get my head around Functional Reactive Programming
by writing a basic explanation of it, following the logic that
explaining something is the best way to understand it.

Am I on the right track with this explanation?

Greetings,

Peter Minten

P.S. Sorry about the long mail, the explanation ended up a little longer
than I originally expected. :)

Document (with markdown formatting) follows:

--8--8--8--8--8--8--8--8--8--8--8--8--8--8--8--8--

This is an attempt to explain Functional Reactive Programming (FRP)
enough to give a reader with no previous exposure to FRP an intuition
what FRP is about. After reading this you should hopefully understand
enough of FRP to understand the
[reactive-banana](http://www.haskell.org/haskellwiki/Reactive-banana)
examples.

FRP has certain terms such as behavior, event and time-varying that can
be confusing for people unfamiliar with it. I'll avoid these terms at
first and will focus on spreadsheets and a generalization of spreadsheet
cells (which I will call boxes). Later, once the most important concepts
are explained, reactive-banana syntax will be introduced along with an
example that demonstrates how to work with behaviors and events in
reactive-banana. Finally some theory about time-varying functions and
how events and behaviors can be implemented using pure functions by
making time explicit should provide the necessary background to
understand reactive-banana's haddock comments.

The version of reactive-banana used here is
[0.5.0.0](http://hackage.haskell.org/package/reactive-banana-0.5.0.0).

Reactive Programming for the Masses: The Spreadsheet


Spreadsheets are something we all (for certain values of we) know about.
Let's talk about a typical, simplified, spreadsheet. We have a list of
products that we sell and want to compute their price with the Value
Added Tax (VAT) added. We might have cells A1 to A10 contain the raw
prices of our products and cell B1 contain the current VAT rate (say 19
for a 19% VAT). In cells C1 to C10 we'd like to see the prices including
VAT.

In cell C1 we'd have a formula: `=A1*(1+B1/100)`, in cell C2
`=A2*(1+B1/100)`, etc. So if A1 contains $100 C1 would contain $119.

But what if the government, in it's eternal quest to reduce the budget
deficit, raises the VAT rate? We'd adjust cell B1, just change it to 20.
And like magic all the C cells are updated.

Though this may seem mundane what we've just seen is actually a very
good example of reactive programming. We didn't tell the C cells to
update; they updated on their own because a value they depend on
changed.

From Cells to Boxes: Generalizing the Spreadsheet
=

Spreadsheets are nice, but if we want to truly get a feel for FRP we'll
have to think beyond them. If we look at a spreadsheet at an abstract
level it pretty much consists of cells of two types: value cells (`19`)
and formula cells (`=A1*(1+B1/100)`). Let's lose the reference to
spreadsheets and talk about boxes.

Say, for now, that there are two kinds of boxes: formula boxes and value
boxes. Both support a get operation that returns a value. Value boxes
additionally support a set operation that sets the value.

Formula boxes can contain any kind of pure function. They can also refer
to the values of other boxes (both formula and value boxes). Value boxes
don't have a function inside them, they have a value.

The translation of our VAT spreadsheet would be something like a formula
box *fIncl1* containing the expression
`get(vExcl1) * (1 + get(vVat) / 100)`. This expression uses two value
boxes: *vExcl1* and *vVat*.

We could also write *fIncl1* using a helper formula box *fVat*. Let
*fVat* have the formula `1 + get(vVat) / 100` and *fIncl1* have the
formula `get(vExcl1) * get(vVat)`. I'll use `:=` for this kind of
definition, the `:=` is there to remind you that this isn't Haskell.

It's important to note that any kind of value may be put into value
boxes, including IO actions and functions.

Try doing this with a spreadsheet:
`fIncls := [get(ve) * get(vVat) | ve - vExcls]`. Or this:
`fIncl1 := apply(get(vVatFunc), get(vExcl1))`.

If you're wondering why I'm not using Haskell syntax, it's to focus on
the meaning of boxes rather than what the functions and combinators
mean. That said, this pseudo-imperative syntax is on its way out as
it's getting too clunky (that `apply` function is really just ugly). For
a quick peek ahead the last few examples would be something like this in
reactive-banana:

fIncls = map (\ve - (*) $ ve * fVat) vExcls
fIncl1 = fVatFunc * vExcl1

Events
==

Let's say we want to build the worlds worst synthesizer. We have 7
buttons: a, b, c, d, e, f and g. Our output is generated
by sampling a box twice per second and playing the frequency in the box
until the next sample is taken.

This can't be expressed with the crude formula and value boxes system
we've had so far