Technology

Functional Reactive Programming in JS, the 10,000ft Overview


I’ve spent the past year working with functional reactive programming (FRP). Some of the problems I’ve noticed is that most of the online resources either:

  • assumes you already know what FRP is
  • assumes you won’t create anything more complex than a toy app
  • focuses on the “reactive” part, ignoring the functional programming

Let’s fix that by answering, “What is functional programming (FP)?””
As per the C2 wiki, a functional programming language provides:

  • first class functions
  • higher order functions
  • closures
  • pattern matching
  • single assignment
  • lazy evaluation
  • garbage collection
  • type inference
  • tail call optimization
  • list comprehensions
  • monads

In case you haven’t realized it, Javascript has some functional programming features:

  1. first class functions — you can assign functions to variables and pass them as arguments
  2. higher order functions — you can create a function that returns a function
  3. closures
  4. single assignment — via const
  5. garbage collection
  6. monads — as far as I can tell, Promises are monad like. (Yea, you’ve used monads without knowing it.)

Before you do an Internet search on the above terms, there’s more to FP. One of the main things is referential transparency:

  • functions cannot modify arguments
  • variables outside of functions should be considered immutable
  • functions cannot store state between successive calls
  • no global, destructive updates

In other words, functions have no side effects. This makes it super easy to reason about programs—you can build up a program from well-behaved functions. (That is, in contrast to OOP, FP modularizes at the function level.)

You may wonder, “How the heck can I build a complex app if functions can’t store state?” More on that in a future post.

We still haven’t answered the question, “What is functional reactive programming?”

functional reactive programming (FRP) is functional programming with asynchronous data streams.

If you know the Observer pattern, then you’re half way to understanding FRP—a data stream is just an Observable i.e., stream === Observable.

The code below creates a stream (in KefirJS) that pushes the values “hello” and “world” to observers.

const myFirstStream = Kefir.stream(emitter => {

    emitter.emit('hello')
    emitter.emit('world')
    emitter.end() //optional

    return () => {}
})

Let’s observe the stream:

myFirstStream.onValue(x => console.log(x))
// 'hello'
// 'world'

What makes FRP so awesome is that you get a very powerful toolkit for manipulating streams.

// map (aka transform) stream values to uppercase
myFirstStream
   .map(x => x.toUpperCase())
   .onValue(x => console.log)
// 'HELLO'
// 'WORLD'
// reduce (aka collect) stream values into a single string
myFirstStream
   .reduce((string, value) => string + value, '')
   .onValue(x => console.log)
// 'helloworld'
// do both
myFirstStream
   .map(x => x.toUpperCase())
   .reduce((string, value) => string + value, '')
   .onValue(x => console.log)
// 'HELLOWORLD'

There is of course more to FRP than map and reduce. Actually, I have a nagging suspicion that almost everything else is just syntactic sugar for (1) map, (2) reduce, and (3) a way to combine streams. True or not, from personal experience, understanding these two functions (specially reduce) will go a long way towards making FRP comprehensible.

From a practical point of view, you can’t go wrong by first learning the corresponding functions for map and reduce in either lodash or underscore.

In case you haven’t noticed, streams generalize Promises. A stream is just a Promise that may or may not end.

To conclude, I know of 4 Javascript FRP libraries:

  • KefirJS – Pros: super fast, super simple. Cons: relatively obscure
  • RxJS – Pros: relatively well known; versions exist for Java. Cons: freakin’ microsoft! Good luck finding comprehensible documentation.
  • BaconJS – Pros: super easy to learn. Ideal for newbies. Cons: Slowest of the libraries, so probably not the best for production code (specially in the backend). Also, because it’s written in CoffeeScript, it probably leaks memory.
  • HighlandJS – Pros: combines Promises, NodeJS Streams, and FRP streams under a single framework (hence the name “highland”). Cons: not performant; not as polished.

UPDATE: The Reactivex tutorial seems to agree… they add concatAll as a must-learn function.

Useful Resources

  1. The aforementioned Reactivex tutorial
  2. The Intro to FRP You’ve been Missing
Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s