How fundamentally different are push-pull and arrowized FRP?

Guillaume Ponce picture Guillaume Ponce · Oct 2, 2014 · Viewed 10.8k times · Source

I want to study FRP in Haskell, but it's a bit difficult to decide on a library to use. Many seem to be dead attempts, some seem to have been resurrected (such as recent activity on Yampa).

From what I read, it seems that there are two "kinds" of FRP: push-pull FRP (like in Reactive-banana and Reflex) on one side and arrowized FRP (like in Yampa) on the other side. It seems that there also used to be some "classic FRP" at the time of Fran and FrTime, but I have not spotted any recent activity in these.

  • Are these two (or three) really fundamentally different approaches of FRP?

  • Is one of them outdated theory whereas the other would be the "stuff of the future"?

  • Or do they have to evolve in parallel, addressing different purposes?

  • Did I name the most prominent library of each category, or are there other options to consider (Sodium, Netwire, et al)?


I finally watched the [talk from Evan Czaplicki](https://www.youtube.com/watch?v=Agu6jipKfYw) recommended in the comments by J. Abrahamson. It is very interesting and did help clarify things up for me. I highly recommend it to anyone who found this question interesting.

Answer

Kevin Caravaggio picture Kevin Caravaggio · Jun 21, 2015

I took a trip to Haskell.org to investigate your question What I found are two important papers you ought to read to further your research, and I am building my answer to your question from these scholarly papers.

Push-Pull FRP by Conal Elliott

Generalising Monads to Arrows by John Hughes


  1. Yes, but also no. According to Elliot, push is data driven FRP evaluation and pull relates to what is called "demand" driven evaluation. The author recommends pull because push tends to idle in between data inputs. Here's the crux: push-pull combines and balances these behaviors for the chief purpose of minimizing the need to recompute values. It's simple; operating FRP with push-pull hastens the ability to react. Arrow is a different technique for using abstract types to link values and evaluate them simultaneously. All these concepts are fundamentally different. But don't take my word for it:

    The nature of the Arrow interface is problematic for the goal of minimal re-evaluation. Input events and behaviors get combined into a single input, which then changes whenever any component changes, (Elliott).

    Thus, Arrow contradicts the goal of push-pull. That does not mean you can't use all of these at once, just that it would be complex, and there are some things you cannot compute without abstract Arrow types.

  2. I have not found scholarly opinions on which approaches are "the way of the future." Only note that arrows can handle simultaneity particularly well. If you could implement arrows and use push-pull to minimize computations, that would be the way of the future.

  3. Yes, they address separate purposes. As I said, they can be formulated together but it is difficult to implement and even if it does work, it would probably negate the reactive speed benefits of push-pull.

  4. That's subjective, but Reactive and Yampa appear to be the most commonly cited language libraries for FRP. I would say Reactive by Conal Elliott has deep roots, and Yampa is established as well. Other projects like Netwire arose as replacements, but it could be awhile before they replace the giants.


Hope this helps! Like I said reading the articles I pointed out will give you a better sense of the semantic distance between arrow, push and pull.