Grapefruit/Comparison to other FRP libraries
First, the implementation of signals differs notably. Grapefruit doesn’t need concurrency. I don’t know yet about performance differences in comparison to Conal’s Reactive library.
Another important difference is the handling of starting times. In Reactive you can start (switch into) signals at different times which may result in catch-up computations. For example, if you have a signal which counts button presses and you only use it after an hour has passed, the increments of all previous button presses will only happen after this hour.
In Grapefruit, the type system is used to force you to age your signals if you want to switch into them later. This is done by the era parameters of signals. See the documentation of FRP.Grapefruit.Signal. For the above example, this means that you have to tell Grapefruit at the beginning that you will switch into your button counter signal later so that Grapefruit can do the increments if the button presses happen.
With Grapefruit, you can view external continuous sources as continuous signals. You can compose continous signals to form new ones. If you finally want to make use of the resulting signals, you sample them. The values of the continuous sources are fetched only at the sample points. Currently, I don’t know how you could create continuous signals from arbitrary external sources in Reactive.
In Grapefruit, continous signals cannot be consumed directly. Instead, they have to be sampled first. So you have always full control over the sampling strategy. You could use a fixed sampling rate, a sample-as-often-as-possible approach or whatever.
The signal types of Grapefruit directly correspond to the types, Conal Elliott mentions in his paper “Simply efficient functional reactivity”. Continuous signals are reactive behaviors, segmented signals are reactive values and discrete signals are events.