Difference between revisions of "Functional Reactive Programming"

From HaskellWiki
Jump to navigation Jump to search
(→‎Introduction: Netwire 4 is now on HackageDB.)
 
(34 intermediate revisions by 12 users not shown)
Line 4: Line 4:
 
== Introduction ==
 
== Introduction ==
 
 
  +
The original formulation of Functional Reactive Programming can be found in the ICFP 97 paper [http://conal.net/papers/icfp97/ Functional Reactive Animation] by Conal Elliott and Paul Hudak. It introduces the following ''semantic functions'':
FRP is about domain-specific languages that capture the notion of
 
time-varying values. Let's take Netwire 4 as an example. You can install it either from HackageDB,
 
   
  +
* <b>at</b> : <i>Behavior<sub>α</sub> → Time → α</i>
cabal install netwire
 
   
  +
* <b>occ</b> : <i>Event<sub>α</sub> → Time × α</i>
or by grabbing the latest source code via darcs:
 
   
  +
to provide a formal description of operations on values now commonly known as ''behaviors'' and ''events''. But what are they?
darcs get http://darcs.ertes.de/netwire/
 
cd netwire
 
cabal install
 
   
  +
=== Behaviors ===
Imagine you have a simple GUI label that displays the number of seconds
 
passed since program start. In an event-based model this is actually
 
quite a complicated task. You would have to create a label and update
 
it all the time using some form of timer/idle event. In Netwire you
 
write:
 
 
myLabel = time
 
   
  +
Traditionally a widget-based user interface is created by a series of imperative actions. First an action is invoked to create an edit widget, then additional actions can be invoked to read its current content, set it to a specific value or to assign an event callback for when the content changes. This is tedious and error-prone.
Now let's say you want to have the same GUI, but the time should start
 
at 10 and pass twice as fast, so you actually want to display twice the
 
number of seconds passed plus 10:
 
 
myLabel = 10 + 2*time
 
   
  +
A better way to represent an edit widget's content is a time-varying value, called a ''behavior''. The basic idea is that a time-varying value can be represented as a function of time:
Imagine you want to display the string "yes" in a label:
 
 
myLabel = "yes"
 
   
  +
<haskell>
Now let's say you want to display "yes", when the space key is held down
 
  +
newtype Behavior a =
and "no" otherwise:
 
  +
Behavior {
 
myLabel = "yes" . keyDown Space <|> "no"
+
at :: Time -> a
  +
}
   
  +
myTodoList :: Behavior Text
You want to display time while pressed and "Press space" while not:
 
  +
yesterday :: Time
 
  +
myTodoList `at` yesterday :: Text
myLabel = fmap show time . keyDown Space <|> "Press space"
 
  +
</haskell>
   
  +
This is only a theoretical model, because a time-varying value can represent something impure like the content of an edit widget, the current value of a database entry as well as the system clock's current time. Using this model the current content of an edit widget would be a regular first class value:
You want to display "yes" every other second and "no" otherwise:
 
 
myLabel = "yes" . holdFor 1 (periodically 2) <|> "no"
 
   
  +
<haskell>
Imagine doing that with event-based code.
 
  +
myEditWidget :: Behavior Text
 
  +
</haskell>
Summary: FRP is about handling time-varying values like they were
 
  +
regular values.
 
  +
In most frameworks there is an applicative interface for behaviors, such that you can combine them easily:
  +
  +
<haskell>
  +
liftA2 (<>) myEdit1 myEdit2
  +
</haskell>
  +
  +
The result is a time-varying value that represents the concatenation of <hask>myEdit1</hask> and <hask>myEdit2</hask>. This could be the value of a third widget, a label, to display the concatenation. The following is a hypothetical example:
  +
  +
<haskell>
  +
do edit1 <- editWidget
  +
edit2 <- editWidget
  +
label <- label (liftA2 (<>) edit1 edit2)
  +
{- ... -}
  +
</haskell>
  +
  +
Without behaviors you would have to write event callback ''actions'' for the edit widgets to ''update'' the label's content. With behaviors you can express this relationship declaratively.
  +
  +
=== Events ===
  +
  +
While behaviours work well for describing properties which are continuous (e.g. the motion of an animated object), other properties are more ''discrete'' (e.g. what button on the mouse was clicked or the screen position where it happened). Events more easily accommodate information like this, by associating the data value of interest with a particular time:
  +
  +
<haskell>
  +
newtype Event a =
  +
Event {
  +
occ :: (Time, a)
  +
}
  +
  +
mouseInWindowNow :: Event Bool
  +
occ mouseInWindowNow :: (Time, Bool)
  +
</haskell>
  +
  +
The concept of an <i>event stream</i> (or simply <i>stream</i>), for representing a series of events, supports a basic model of interactivity:
  +
  +
<div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote">
  +
Suppose that we want to compute a function <i>F</i> on several arguments <i>A</i><sub>0</sub>, <i>A</i><sub>1</sub>, <i>A</i><sub>2</sub>,... appearing consecutively in time [as discrete events]. One can view this so-called <i>stream</i> (<i>A</i><sub>0</sub>, <i>A</i><sub>1</sub>, <i>A</i><sub>2</sub>,...) as a potentially infinite list <i>A</i> = (<i>A</i><sub>0</sub>:<i>A</i><sub>1</sub>:<i>A</i><sub>2</sub>:···:<i>A</i><sub>n</sub>:⊥) where ⊥ stands for “unspecified” and is interactively updated to <i>A</i><sub>n+1</sub>:⊥ each time the user has a new argument <i>A</i><sub>n+1</sub>. Then on this list <i>A</i>, the system applies the function <i>F</i><sup>*</sup> defined by
  +
::<i>F</i><sup>*</sup> (<i>A</i>:<i>B</i>) = (<i>F</i> <i>A</i>):(<i>F</i><sup>*</sup> <i>B</i>)
  +
  +
obtaining
  +
::<i>F</i><sup>*</sup> <i>A</i> = (<i>F</i> <i>A</i><sub>0</sub>:<i>F</i> <i>A</i><sub>1</sub>:<i>F</i> <i>A</i><sub>2</sub>:···:<i>F</i> <i>A</i><sub>n</sub>:<i>F</i><sup>*</sup> ⊥)
  +
  +
also appearing consecutively in time.
  +
  +
<tt>[https://repository.ubn.ru.nl/bitstream/handle/2066/17230/13246.pdf Functional Programming and Lambda Calculus], Henk Barendregt (page 325).</tt>
  +
</div>
  +
  +
== Semantic functions? ==
  +
  +
From page 6 of [http://conal.net/papers/icfp97/icfp97.pdf the paper]:
  +
<div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote">
  +
An early implementation of Fran represented behaviors as implied in the formal semantics:
  +
<haskell>
  +
data Behavior a = Behavior (Time -> a)
  +
</haskell>
  +
This representation, however, leads to a serious inefficiency [a “space-time” leak].
  +
</div>
  +
  +
So instead of one canonical implementation of FRP, this tendency to "leak" has led to a variety of implementations, each with its own benefit-cost trade-offs.
   
 
== Libraries ==
 
== Libraries ==
* [http://hackage.haskell.org/package/sodium Sodium]
 
* [[Grapefruit]]
 
* [[Reactive]]
 
 
* [[DataDriven]]
 
* [[DataDriven]]
* [[Yampa]]
 
* [[WxFruit|wxFruit]]
 
 
* [http://hackage.haskell.org/package/elerea Elerea]
 
* [http://hackage.haskell.org/package/elerea Elerea]
* [[Reactive-banana|reactive-banana]]
 
* [[Netwire]]
 
 
* [http://conal.net/fran/ Fran] (discontinued)
 
* [http://conal.net/fran/ Fran] (discontinued)
  +
* [[Grapefruit]]
* [http://hackage.haskell.org/packages/archive/pkg-list.html#cat:frp Hackage packages in the category FRP]
 
  +
* [[Netwire]]
 
  +
* [[Reactive]]
  +
* [[Reactive-banana|reactive-banana]]
  +
* [https://reflex-frp.org/ Reflex]
  +
* [http://hackage.haskell.org/package/sodium Sodium]
  +
* [[WxFruit|wxFruit]]
  +
* [[Yampa]]
  +
* [[https://github.com/ivanperez-keera/dunai Dunai]]
  +
* [[Rhine]]
  +
* [http://hackage.haskell.org/packages/archive/pkg-list.html#cat:FRP Hackage packages in the category FRP]
  +
A simple, practical comparison between FRP libraries is done by [https://github.com/gelisam/frp-zoo frp-zoo]
   
 
== Publications and talks ==
 
== Publications and talks ==
  +
* [http://www.cs.rit.edu/~eca7215/frp-independent-study/Survey.pdf A Survey of Functional Reactive Programming]
 
  +
* [https://www.youtube.com/watch?v=zgNRM8tZguY ICFP 2014: Settable and Non-Interfering Signal Functions for FRP - Daniel Winograd-Cort] (video)
  +
* [https://web.archive.org/web/20150217184805/https://www.cs.rit.edu/~eca7215/frp-independent-study/Survey.pdf A Survey of Functional Reactive Programming]
 
* [http://conal.net/papers/frp.html Conal Elliott’s FRP-related publications]
 
* [http://conal.net/papers/frp.html Conal Elliott’s FRP-related publications]
* [https://grapefruit-project.org/publications-and-talks Grapefruit-related publications and talks]
+
* [https://wolfgang.jeltsch.info/publications-and-talks Grapefruit-related publications and talks]
* [http://haskell.cs.yale.edu/?page_id=65#FunctionalReactiveProgramming The Yale Haskell Group’s FRP-related publications]
+
* [https://web.archive.org/web/20171012164802/http://haskell.cs.yale.edu/publications/#FunctionalReactiveProgramming The Yale Haskell Group’s FRP-related publications] (archived)
  +
* [https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.11.6997&rep=rep1&type=pdf FROB: A Transformational Approach to the Design of Robot Software - Gregory D. Hager and John Peterson]
  +
* [https://begriffs.com/posts/2015-07-22-essence-of-frp.html The Essence of FRP (Conal Elliott -- July 22, 2015 -- video)]
  +
* [https://begriffs.com/posts/2016-07-27-tikhon-on-frp.html A Sensible Intro to FRP (Tikhon Jelvis -- July 27, 2016 -- video)]
   
  +
== Books ==
  +
* Blackheath, Stephen; Jones, Antony. [http://www.manning.com/blackheath Functional Reactive Programming]. Manning Publications (2015). p.245. ISBN 978-1-6334-3010-5
   
 
== Blog posts ==
 
== Blog posts ==
  +
  +
* [https://github.com/gelisam/frp-zoo frp-zoo]; comparing many FRP implementations by reimplementing the same toy app in each.
  +
* [http://blog.reactiveprogramming.org/ Functional Reactive Programming, a better way to build interactive applications] (about the Sodium FRP Library currently for C#, C++, Haskell and Java and more to come)
 
* [http://apfelmus.nfshost.com/blog.html#functional-reactive-programming-frp FRP-related posts on Heinrich Apfelmus’ blog]
 
* [http://apfelmus.nfshost.com/blog.html#functional-reactive-programming-frp FRP-related posts on Heinrich Apfelmus’ blog]
 
* [http://conal.net/blog/tag/frp FRP-related posts on Conal Elliott’s blog]
 
* [http://conal.net/blog/tag/frp FRP-related posts on Conal Elliott’s blog]
Line 78: Line 133:
 
* [http://lukepalmer.wordpress.com/2008/11/28/relative-time-frp/ Relative time FRP] by Luke Palmer
 
* [http://lukepalmer.wordpress.com/2008/11/28/relative-time-frp/ Relative time FRP] by Luke Palmer
 
* [http://blog.edwardamsden.com/2011/03/demonstrating-time-leak-in-arrowized.html Demonstrating a Time Leak in Arrowized FRP] by Edward Amsden
 
* [http://blog.edwardamsden.com/2011/03/demonstrating-time-leak-in-arrowized.html Demonstrating a Time Leak in Arrowized FRP] by Edward Amsden
  +
* [https://www.reddit.com/r/haskell/comments/3fr5ij/frp_systems_discussion/ FRP Systems discussion] on reddit
 
  +
* [https://t0yv0.blogspot.com/2014/07/the-fatal-attraction-of-frp.html The fatal attraction of FRP] by Anton Tayanovskyy (about the WebSharper UI.Next framework for single-page JavaScript applications)
   
 
== People ==
 
== People ==
Line 90: Line 146:
 
* [https://wolfgang.jeltsch.info/ Wolfgang Jeltsch]
 
* [https://wolfgang.jeltsch.info/ Wolfgang Jeltsch]
 
* [http://www.cs.nott.ac.uk/~nhn/ Henrik Nilsson]
 
* [http://www.cs.nott.ac.uk/~nhn/ Henrik Nilsson]
  +
* [http://github.com/ivanperez-keera Ivan Perez]
 
* [http://mcis.western.edu/~jpeterson/ John Peterson]
 
* [http://mcis.western.edu/~jpeterson/ John Peterson]
  +
* Ertugrul Söylemez
  +
  +
== History ==
  +
  +
=== A possible predecessor? ===
  +
  +
In his thesis [https://core.ac.uk/download/9835633.pdf Functional Real-Time Programming: The Language Ruth And Its Semantics], some parts of the semantics Dave Harrison gives for ''Ruth'' bears a curious resemblance to those for FRP:
  +
  +
* <small>(page 48)</small>
  +
:{|
  +
|<div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote">
  +
A channel is an infinite stream of timestamped data values, or messages, each message denoting an event in the system. [...]
  +
</div>
  +
<sup> </sup>
  +
<haskell>
  +
type Channel a = [Event a]
  +
data Event a = At Time a
  +
</haskell>
  +
|}
  +
  +
* <small>(page 61)</small>
  +
:{|
  +
|<div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote">
  +
In the semantics given in Chapter 5 every <i>Ruth</i> program is supplied with a tree of time values (or clock) as suggested in [https://academic.oup.com/comjnl/article-pdf/31/3/243/1157325/310243.pdf this paper] and each <i>Ruth</i> process is given a different sub-tree of the clock [...]
  +
</div>
  +
<sup> </sup>
  +
<haskell>
  +
type Program = Clock -> ...
  +
type Process a = Clock -> a
  +
  +
type Clock = Tree Time
  +
left :: Clock -> Clock
  +
right :: Clock -> Clock
  +
</haskell>
  +
<sup> </sup>
  +
<div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote">
  +
A clock tree is composed of a node holding a non-negative integer denoting the current time and two sub-trees containing the times of future events. As the tree is (lazily) evaluated each of the nodes is instantiated with the value of system time <i>at the time at which the node is instantiated</i>, thus giving programs reference to the current time. [...]
  +
</div>
  +
<sup> </sup>
  +
<haskell>
  +
type Time = Integer -- must be zero or larger
  +
data Tree a = Node { contents :: a,
  +
left :: Tree a,
  +
right :: Tree a }
  +
  +
currentTime :: Clock -> Time
  +
currentTime = contents
  +
</haskell>
  +
|}
  +
  +
Regarding Harrison's semantics:
  +
<div style="border-left:1px solid lightgray; padding: 1em" alt="blockquote"><small>(page 53)</small>
  +
  +
The semantics of <i>Ruth</i> given in Chapter 5 assume a normal order evaluation strategy such as is provided by the technique of lazy evaluation [...]. Consequently <code>whererec</code> can be used to define infinite data structures.
  +
</div>
   
 
[[Category:FRP|*]]
 
[[Category:FRP|*]]

Latest revision as of 05:58, 7 November 2022

Functional Reactive Programming (FRP) integrates time flow and compositional events into functional programming. This provides an elegant way to express computation in domains such as interactive animations, robotics, computer vision, user interfaces, and simulation.


Introduction

The original formulation of Functional Reactive Programming can be found in the ICFP 97 paper Functional Reactive Animation by Conal Elliott and Paul Hudak. It introduces the following semantic functions:

  • at : Behaviorα → Time → α
  • occ : Eventα → Time × α

to provide a formal description of operations on values now commonly known as behaviors and events. But what are they?

Behaviors

Traditionally a widget-based user interface is created by a series of imperative actions. First an action is invoked to create an edit widget, then additional actions can be invoked to read its current content, set it to a specific value or to assign an event callback for when the content changes. This is tedious and error-prone.

A better way to represent an edit widget's content is a time-varying value, called a behavior. The basic idea is that a time-varying value can be represented as a function of time:

newtype Behavior a =
    Behavior {
      at :: Time -> a
    }

myTodoList                :: Behavior Text
yesterday                 :: Time
myTodoList `at` yesterday :: Text

This is only a theoretical model, because a time-varying value can represent something impure like the content of an edit widget, the current value of a database entry as well as the system clock's current time. Using this model the current content of an edit widget would be a regular first class value:

myEditWidget :: Behavior Text

In most frameworks there is an applicative interface for behaviors, such that you can combine them easily:

liftA2 (<>) myEdit1 myEdit2

The result is a time-varying value that represents the concatenation of myEdit1 and myEdit2. This could be the value of a third widget, a label, to display the concatenation. The following is a hypothetical example:

do edit1 <- editWidget
   edit2 <- editWidget
   label <- label (liftA2 (<>) edit1 edit2)
   {- ... -}

Without behaviors you would have to write event callback actions for the edit widgets to update the label's content. With behaviors you can express this relationship declaratively.

Events

While behaviours work well for describing properties which are continuous (e.g. the motion of an animated object), other properties are more discrete (e.g. what button on the mouse was clicked or the screen position where it happened). Events more easily accommodate information like this, by associating the data value of interest with a particular time:

newtype Event a =
    Event {
      occ :: (Time, a)
    }

mouseInWindowNow     :: Event Bool
occ mouseInWindowNow :: (Time, Bool)

The concept of an event stream (or simply stream), for representing a series of events, supports a basic model of interactivity:

Suppose that we want to compute a function F on several arguments A0, A1, A2,... appearing consecutively in time [as discrete events]. One can view this so-called stream (A0, A1, A2,...) as a potentially infinite list A = (A0:A1:A2:···:An:⊥) where ⊥ stands for “unspecified” and is interactively updated to An+1:⊥ each time the user has a new argument An+1. Then on this list A, the system applies the function F* defined by

F* (A:B) = (F A):(F* B)

obtaining

F* A = (F A0:F A1:F A2:···:F An:F* ⊥)

also appearing consecutively in time.

Functional Programming and Lambda Calculus, Henk Barendregt (page 325).

Semantic functions?

From page 6 of the paper:

An early implementation of Fran represented behaviors as implied in the formal semantics:

data Behavior a = Behavior (Time -> a)

This representation, however, leads to a serious inefficiency [a “space-time” leak].

So instead of one canonical implementation of FRP, this tendency to "leak" has led to a variety of implementations, each with its own benefit-cost trade-offs.

Libraries

A simple, practical comparison between FRP libraries is done by frp-zoo

Publications and talks

Books

Blog posts

People

History

A possible predecessor?

In his thesis Functional Real-Time Programming: The Language Ruth And Its Semantics, some parts of the semantics Dave Harrison gives for Ruth bears a curious resemblance to those for FRP:

  • (page 48)

A channel is an infinite stream of timestamped data values, or messages, each message denoting an event in the system. [...]

type Channel a = [Event a]
data Event a   = At Time a
  • (page 61)

In the semantics given in Chapter 5 every Ruth program is supplied with a tree of time values (or clock) as suggested in this paper and each Ruth process is given a different sub-tree of the clock [...]

type Program = Clock -> ...
type Process a = Clock -> a

type Clock = Tree Time
left  :: Clock -> Clock
right :: Clock -> Clock

A clock tree is composed of a node holding a non-negative integer denoting the current time and two sub-trees containing the times of future events. As the tree is (lazily) evaluated each of the nodes is instantiated with the value of system time at the time at which the node is instantiated, thus giving programs reference to the current time. [...]

type Time   = Integer  -- must be zero or larger 
data Tree a = Node { contents :: a,
                     left     :: Tree a,
                     right    :: Tree a }

currentTime :: Clock -> Time
currentTime = contents

Regarding Harrison's semantics:

(page 53)

The semantics of Ruth given in Chapter 5 assume a normal order evaluation strategy such as is provided by the technique of lazy evaluation [...]. Consequently whererec can be used to define infinite data structures.