
Am Freitag, 6. März 2009 14:34 schrieb Daniel Bünzli:
without using recursive signal functions,
If this is because there's this limitation in the frp system you use
It is.
then better fix the system.
The system is Grapefruit, by the way. And I’m its developer, by the way. :-) I have to say that it’s hard, if not impossible, to combine recursive signal definitions with other features, I want to have. The point of recursive definitions is that you want to turn recursive equations from your problem domain directly into Haskell definitions. This is nice from a user’s point of view but hard from a programmers point of view. Standard Haskell already shows that. While it is possible to define an infinite list of ones by ones = 1 : ones, it is not possible to do the same for sequences of type Seq. The above definition of ones relies very much on the structure of lists. Analogously, the ability to define signals recursively restricts the set of possible signal implementations seriously. Haskell’s recursive definitions are very general. They have to find fixpoints of arbitrary functions over arbitrary type. Therefore, their semantics are rather weak. They give you the least defined fixpoint. The consequence is that you get bottom if you use something like x = 0 * x although x = 0 might be what you prefered. What I want to say is that coming up with a signal implementation that allows Haskell recursion and has other advantages at the same time is a big challenge. There are three features, you might want from a signal implementation: 1. support for recursive signal definitions using Haskell equations 2. memoization (for avoiding time leaks, for example) 3. signals which may depend on external sources I tried hard to support 2 and 3 well in Grapefruit. Fran has 1 but has problems with 2 and 3. I don’t know whether Reactive has a solution for 2 in the context of recursive definitions, i.e., whether the space and time leak problems of Fran were solved. I think, it has at least problems with 3. For me, 2 and 3 are more important than 1. One reason is that 1 has other problems than being in conflict with 2 and 3. The result of a recursively defined signal depends on when sampling occurs. Since a recursive definition tends to result in accumulation of values, errors introduced by sampling may accumulate too. So you have to use clever approximation algorithms in addition. My new idea is to view the problem in a different way. Let’s take the problem where the position of a ball is the integral of the difference between the mouse position and the ball position. As far as I can see, the transformation of the mouse position signal into the ball position signal forms a linear system. So the ball position signal is the mouse position signal convoluted with another signal. If we would have a function that performes convolution, we could probably implement many problems using this function. Using convolution would let us get rid of the problems with accumulating errors. I suppose that most of the recursive definitions you would use in FRP are differential or integral equations. Let’s look at the equation for the ball-following-the-mouse example: ballPos = integral (mousePos - ballPos) ballPos can be represented in terms of mousePos as follows: ballPos = (exp . negate) * mousePos where * means convolution. We could provide a library which supports common stuff like distance-dependent acceleration, friction etc. Of course, you could say that now the programmer isn’t able anymore to enter his equations directly which isn’t nice. However, this situation is not different to other areas. For example, you cannot write x = 5 - x / 2 and expect x to be 10 / 3. Instead, you have to transform the equation first.
Soon or later it you'll want it elsewhere. A recursive reactive signal just means that some of what your reactive program computed will be usefull/necessary for the next step.
You can do this with convolution, I think. By the way, continuous signals don’t have steps. These are just introduced by sampling.
You'll see that happen very quickly (e.g. any simple reactive state machine).
“State machine” sounds like a discrete problem. You can use accumulation over event sequences here (as, for example, provided by the scan function in FRP.Grapefruit.Signal.Discrete). By the way, the adress of the Grapefruit mailing list is grapefruit@projects.haskell.org, not grapefruit@haskell.org. Best wishes, Wolfgang