liveBook · Manning

Functional reactive programming

As explained in Functional Design and Architecture: Examples in Haskell

A functional reactive pipeline is a composition of functional processing stages that propagates changing or time-varying values through a data-flow structure.

Functional reactive programming (FRP) combines reactive programming with functional ideas. It models time-varying values as signals, also called behaviors: when one value depends on another, changes propagate automatically. Events can occur, change, repeat, or disappear, so they can be treated as time-dependent values and bound to reactions. section 2.1.2

A reactive network composes signals with actions. Functional reactive streams express a closely related data-flow model: continuous, time-ordered event streams can be mapped, merged, divided, or zipped into new streams, and changes or absences can trigger actions. This makes the approach useful for GUI behavior, complex business logic, and interoperability code. section 2.1.2 section 3.1.4

Build a pipeline around explicit flow of changing values:

  • Produce readings continuously from an external source rather than placing all work in a single sequential control script. section 3.1.4
  • Transform or normalize each value in a focused operation before downstream processing. section 3.1.4
  • Consume each emitted value in a monitor that stores it, validates it, logs failures, raises alarms, and yields a result. section 3.1.4

Temperature-monitoring flow

A thermReadings stream reads an outside thermometer once a second and yields each reading. A thermMonitor stream receives each reading, stores it, validates temperature bounds, logs and raises an alarm on failure, then yields the validation result. The stream separates value production from monitoring reactions while preserving a direct flow from sensor input to external notification. section 3.1.4

FRP can also serve as an architectural boundary. An interoperability bus may be implemented with an FRP library and connect database and GUI accessors, while the wider application relates presentation, business logic, database, initialization, configuration, and global state through explicit component relations. section 3.2.3

Listing 3.6 Thermometer monitor stream
Stream: thermMonitor                        #1
Description: temperature monitor
Given: for @reading in thermReadings        #2
  
  Store @reading                            #3
  
  validateTemperature(@reading),            #4
    Result: @result
  
  If @result == (Failure, @message) Then    #5
    Log @reading
    Raise alarm @message
 
  Yield @result                             #6
 
Scenario: validateTemperature               #7
Description: validate temperature
Parameters: (@time, @temp, @therm)
Invocation: on call
 
  If @temp < 263.15K Then
    Return (Failure, "Outside T < than bound for " + @therm)
  Else If @temp > 323.15K Then
    Return (Failure, "Outside T > than bound for " + @therm)
  Else Return Success

Inspect the monitor stream to see one emitted reading pass through storage, validation, failure handling, and result emission. section 3.1.4

How Functional Design and Architecture: Examples in Haskell covers it

How deep it goes
Defines signals and stream operations, then works through a two-stream temperature-monitoring flow without detailing an FRP library implementation.
Examples
Uses periodic outside-thermometer readings, Kelvin conversion, persistence, bound validation, logging, alarms, and a monitor stream.
What you can do after
Apply it via streams to wrap value-reading and transformation processes into a reactive domain model.
How it connects
Connects signals, behaviors, reactive streams, data flow, GUIs, business logic, monads, and free monad interfaces.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Design and Architecture: Examples in Haskell. The section links point to the parts of the book it draws on.