
Peter Minten
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 Now both the predefined event function 'after' and the predefined signal 'currentTime' are signal functions. It also allows to implement some analysis tools easily: -- Emit an event whenever the given signal function's output -- changes: changesOf :: (Eq b) => SF a b -> SF a (Maybe b) Finally there is an extension of AFRP of which I'm the proud inventor. =) By generalizing the automaton arrow to allow what I call signal inhibition you get to the wire arrow. This adds another layer of flexibility, unifies the notions of time-varying functions and events and completely removes the need for switching. Events can now be handled implicitly. The library Netwire implements this concept. Conceptionally: Wire a b = a -> (Maybe b, Wire a b) Event = Wire changesOf :: (Eq b) => Wire a b -> Wire a b alterTime = fullTime <|> halfTime fullTime = when (even . floor) . time halfTime = fmap (/ 2) time Greets, Ertugrul -- nightmare = unsafePerformIO (getWrongWife >>= sex) http://ertes.de/