
Peter Minten 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?
I think so. Your explanation looks fine to me, except for one really subtle but really important issue:
Stepped sounds a lot like stepper and we can create that function by making a few small adjustments.
type Time = Int stepper :: a -> [(Time, a)] -> (Time -> a) stepper d es = \t -> case takeWhile (\(t', _) -> t' <= t) es of [] -> d xs -> snd (last xs)
The correct definition of stepper uses < instead of <= ... case takeWhile (\(t', _) -> t' < t) es of ... In other words, at the moment t == t' , the behavior still returns the "old" value, not the "new" value from the event. This important because it allows for recursive definitions, like let b = accumB 1 e e = (+) <$> b <@ eKey If you were to use <= here, then the new value of the behavior would depend on itself and the result would be undefined. (Actually, even if you use the correct definition for stepper, trying to implement Event and Behavior in terms of [(Time,a)] and Time -> a in Haskell would give undefined on this recursive example. That's because the data types still aren't lazy enough, you have to use another model. That's one reason why implementing FRP has traditionally been hard.)
P.S. Sorry about the long mail, the explanation ended up a little longer than I originally expected. :)
I know it was time to get a blog when my mailing list posts got too long. ;) Best regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com