Skip to content

Instantly share code, notes, and snippets.

@puffnfresh
Created December 4, 2013 23:01
Show Gist options
  • Save puffnfresh/7797202 to your computer and use it in GitHub Desktop.
Save puffnfresh/7797202 to your computer and use it in GitHub Desktop.
Promises as functors are useful.
var Promise = require('fantasy-promises'),
fl = "https://api.github.com/repos/fantasyland/",
// Pretend this URL is given by the user, not setTimeout
userInput = new Promise(function(resolve) {
setTimeout(function() {
resolve(fl + "fantasy-states");
}, Math.random() * 500);
}),
// We should be able to reuse this function. Functors compose, so
// we map then map to change a value.
watchers = compose(map)(map)(function(o) {
return o.watchers;
});
// Uses node.js to send a http request, JSON deserialises the response
function makeRequest(url) {
var http = require('https'),
urlOptions = require('url').parse(url);
urlOptions['headers'] = { 'User-Agent': 'node.js' };
return new Promise(function(resolve) {
var body = '';
http.get(urlOptions, function(response) {
response.on('data', function(chunk) {
body += chunk;
});
response.on('end', function() {
resolve(JSON.parse(body));
});
});
});
}
// Runs a promise, prints the results
function run(p) {
p.fork(function(result) {
console.log(result);
});
}
// identity(a) = a
function identity(a) {
return a;
}
// compose(f)(g)(x) = f(g(x))
function compose(f) {
return function(g) {
return function(x) {
return f(g(x));
};
};
}
// map(f)(o) == o.map(f)
function map(f) {
return function(o) {
return o.map(f);
};
}
// flatten(o) == o.chain(identity)
function flatten(o) {
return o.chain(identity);
}
// Id constructor - trivial functor
function Id(value) {
this.value = value;
}
Id.prototype.map = function(f) {
return new Id(f(this.value));
};
// Id of promise
run(watchers(new Id(fl + "fantasy-options").map(makeRequest)).value);
// Array of promises
watchers([fl + "fantasy-promises", fl + "fantasy-lenses"].map(makeRequest)).forEach(run);
// Promise of promise
run(flatten(watchers(userInput.map(makeRequest))));
// Notice that most of the above code is reused for different
// structures. The only common operation is `map`. This means we're
// working across Functors.
// We could make the Promise case a little more direct but then we
// wouldn't have the same function which worked over many of our
// structures. I love code reuse.
// Sadly, Promises/A+ doesn't have a Functor, because it only has
// `then` which is almost like `map` but has a special case for
// functions which return an object with a `then` property. In other
// words, it's not parametric. We might be able to work around that by
// wrapping results or something.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment