You could probably say that this library implements a form of reactive programming using transducers with `asCallback` and `asyncCallback`. In fact, many ideas for this library were rooted in my exploration of ReactiveCocoa a few years back [1]. I think that transducers lead to a much cleaner implementation and I may resurrect that library to be based on underscore-transducer and add more reactive extensions. (Also, the 'r' in `_r` stands for "reactive".)
I really like the way transducers abstract the process of iteration from the transformation that makes this possible.
(I'd also add in Elliott's denotational design aspects, but those sort of become dicier with respect to arrowized FRP.)
Reactive Programming is a more general term and is often applied to any kind of synchronous (and sometimes even asynchronous) stream processing. I think it's utter buzz and appreciate Eric Meijer's talk[0] about what "reactive" tends to mean (push and pull streams, fine tuned effect handling).
Now, if you're doing regular old stream processing then you can hook up whatever kind of event handlers you like, push and pull. Transducers form a framework for achieving some of these kinds of transformations as they encode one-to-many transforms (with ambient local state as available in Clojure and all the early termination business, but basically just a -> [b]). In some sense they're nearly "arrowized" as you're focusing on the transformation of "reactive" quantities, but they're certainly discretized and tied to sampling rates in their formulation.
[0] http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2014/Key...
Reactive Programming is thrown in there for good measure as well, but typically "reactive" applies to anything which is synchronous or asynchronous programming but usually does not abstract sampling rate at all.
The upshot is that FRP is the most uncertain today and also the most composable. Reactive Programming is mostly programming with asynchronous streams and is a little ad hoc and, ultimately, a really wide space of approaches.
Transducers are a very particular tool for constructing "container transformers" which might be used to build some small piece of a reactive programming system. Mostly likely they'll not be used in a true FRP system because they understand the notion of discrete updates which break the composability of FRP.
A transducer is composable algorithmic transformation, that is independent of input and output sources and the process of iteration [1].
The threading macro `-->` reorders execution of a list of forms, inserting the first form as the last item of the second, etc. Composition of transducers apply transformations in the same order.
Essentially all transducer transformations are defined as a series of steps, where each step is possibly advanced (0 or more times) by each transformation by a function similar to what you pass `reduce`: `memo = step(memo, item)`. When you execute a transducer, you supply the step function, the initial memo, and each item when iterating. This allows you to abstract the input, output, and iteration outside the transformation (these are implementation details normally provided by the library).
You can define `map` as a form of `reduce`: `memo = step(memo, mappingFn(item))`, which allows you to create a transducer for `map`.
Remember that the step function and initial memo are supplied outside the transformation. But, as an example, if you are transducing over arrays, the initial memo is an empty array, the step function appends each item to the array and returns the modified array, and the return value is used as the memo (result) of the next iteration of `step`. This step function is executed for every item in a source array using some process of iteration (normally a reduce, but does not have to be).