Monadic signals for asynchronous and reactive programming
npm install m-signal#m-signal
Monadic signals for asynchronous and reactive programming. Still under development, but should be usable.
##API
signal(source)
Creates a signal. source should be a function that takes one argument: a function that source calls when it wants to add a value to the signal.
signal.unit(value)
Creates a signal with value as its only value. (Part of being a monad, and equivalent to monadic return.)
signal.combine(...signals)
Takes a number of signals and combines them into one signal that broadcasts the current value of each signal as an array when any signal changes.
signal.lift(f)
Takes a function and returns an equivalent where each argument and the return value are all signals containing the same type as the original function.
###Methods of signals
In the following descriptions, s is any signal. All methods return a new signal except for listen.
s.fmap(f)
Returns a signal with every value broadcast by s passed through the function f. Analogous to map for arrays.
s.bind(f)
f should be a function that takes a value broadcast by s and returns a signal. The signal returned by bind then broadcasts the values of these signals whenever one of them updates.
s.fold(f, i)
For each value from f, passes the previous return value of f and the new value to f and broadcasts the return value. i is used as the initial first argument to f.
s.apply(s2)
This only works if the values of s are functions. When s or s2 is updated, broadcasts the result of calling the current value of s with the current value of s2.
s.listen(f)
Whenever s broadcasts a value, f is called with that value. Note that the value can be the same as the previous one and that if s has already broadcast a value when listen is called, f will be immediately called with the current value of s.
###Types
(In my own imagined TypeScript/Haskell hybrid type system, hopefully it's comprehensible.)
```
type Signal
fmap: (T => U) => Signal,
bind: (T => Signal) => Signal,
fold: ((U, T) => U, U) => Signal,
apply: V = T> Signal => Signal
listen: (T => void) => void
};
signal ::
signal.unit :: U => Signal
signal.combine ::
signal.lift ::
##Examples
###FRP
`
var signal = require('msignal');
function mouseSignal() {
return signal(function(resolve) {
window.addEventListener("mouseup", function(e) { resolve(false); });
window.addEventListener("mousedown", function(e) { resolve(true); });
});
}
// Logs the number of clicks
mouseSignal()
.fold(function(sum, mouse) { return mouse ? sum + 1 : sum; }, 0)
.listen(console.log.bind(console));
`
###Promise-y
`
var signal = require('msignal');
function ajaxGet(url) {
return signal(function(resolve) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200)
resolve(xhr.responseText);
};
xhr.send();
});
}
ajaxGet("http://reddit.com/r/javascript/about.json")
.fmap(function(json) {
return JSON.parse(json).data.description_html;
})
.listen(console.log.bind(console));
``