Skip to content

Instantly share code, notes, and snippets.

@danclien
Last active August 29, 2015 14:10
Show Gist options
  • Save danclien/82e13a62787db396cb44 to your computer and use it in GitHub Desktop.
Save danclien/82e13a62787db396cb44 to your computer and use it in GitHub Desktop.
// In Haskell, a type that implements the Monad type class has the following functions:
//
// return :: a -> m a
// bind :: m a -> (a -> m b) -> m b
//
// The Monad type classes could have also been implemented as:
//
// return :: a -> m a
// fmap :: (a -> b) -> m a -> m b
// join :: m (m a) -> m a
//
// Given `fmap` and `join`, `bind` could be implemented as:
//
// bind = join . fmap
//
// In the JavaScript example below:
//
// return a => Promise(a);
// fmap func promise => promise.map(func);
// join promise => promise.join();
//
// This code still needs a bit of clean up.
function Promise(x) {
var callbacks = [];
var addCallback = function(cb) {
callbacks.push(cb);
}
var resolve = function(x) {
if (this.value !== undefined) {
return;
}
this.value = x;
callbacks.forEach(function(cb) {
cb(x);
});
}
var map = function(f) {
var deferred = new Promise();
if (this.value === undefined) {
addCallback(function(value) {
deferred.resolve(f(value));
});
} else {
deferred.resolve(f(this.value));
}
return deferred;
}
var join = function() {
var deferred = new Promise();
var innerPromise = this.value;
var resolved = innerPromise !== undefined;
var innerResolved = resolved && innerPromise.value !== undefined;
if (resolved && innerResolved) {
// Resolve the deferred in both the inner and outer promises are resolved
deferred.resolve(innerPromise.value);
} else if (resolved && !innerResolved) {
// Add a callback since the inner promise is not resolved
innerPromise.addCallback(function(value) {
deferred.resolve(value);
})
} else {
// Add a callback since the outer promise is not resolved
addCallback(function(innerPromise) {
if(innerPromise.value !== undefined) {
deferred.resolve(innerPromise.value);
} else {
innerPromise.addCallback(function(value) {
deferred.resolve(value);
});
}
});
}
return deferred;
}
var bind = function(f) {
return map(f).join();
}
return {
bind: bind,
join: join,
map: map,
resolve: resolve,
value: x,
addCallback: addCallback
};
}
// map
var a = Promise(10);
var b = a.map(function(x) { return x + 1; });
// Chained maps
var c = Promise();
var d = c.map(function (x) { return x + 1; });
var e = d.map(function (x) { return x + 10; });
c.resolve(31);
// join
var f = Promise(Promise(10));
var g = f.join();
// bind
var h = Promise();
var i = h.bind(function(value) { return Promise(value + 1) });
h.resolve(10);
// Nested binds
var j = Promise();
var k = Promise();
var l = j.bind(function(v1) {
return k.bind(function(v2) {
return Promise(v1 + v2);
});
});
j.resolve(10);
k.resolve(32);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment