Closed mudge closed 11 years ago
Wondering if @puffnfresh and @raganwald have something to add.
I vote yes. Makes it something like the common Semigroup for Either. Which goes something like this:
class Semigroup a where
concat :: a -> a -> a
instance Semigroup r => Semigroup Either l r where
concat (Right a) (Right b) = Right (concat a b)
concat (Left l) _ = Left l
concat _ (Left l) = Left l
One thing that might be tricky is if both promises are rejected:
var z = x.concat(y);
x.reject('Foo');
y.reject('Bar');
z.onRejected(function (reason) {
console.log('What is', reason, '?');
});
Should it fire with both reasons? If so, that violates the idea that promises can only be moved into a fulfilled or rejected state once (subsequent calls are idempotent).
The alternative here is that concatenating promises returns a new promise containing only the concatenation of their values and doesn't bring across state at all.
var z = x.concat(y);
x.reject('Foo');
y.reject('Bar');
z.reject('Baz');
z.onRejected(function (reason) {
console.log('I am fired with Baz only.');
});
But this does feel a little odd. You could argue that concat
is returning a wholly new promise disconnected from the original x
and y
but this behaviour is surprising: if x
fails, for example, you'd want to know even if you only interrogate z
.
@mudge see the Haskell above. Either errors take the first error (i.e. x concat y == x, if x is an error).
Also, couldn't there be multiple instances of Semigroup for Promise?
Ah, thanks @puffnfresh. This should be relatively easy to do with something like:
/* concat :: Promise a -> Promise a */
Promise.prototype.concat = function (other) {
var promise = new Promise();
this.map(function (x) {
other.map(function (y) {
promise.resolve(x.concat(y));
});
});
this.onRejected(function (reason) {
promise.reject(reason);
});
other.onRejected(function (reason) {
promise.reject(reason);
});
return promise;
};
@ehd yes, wrappers to get different semigroups would be great.
It should be easy to provide a wrapper for both first-rejection and concatenated-rejection but the age-old question is what should the alternate functions be called? Is there a standard already?
I'm not aware of a standard. Would we have to implement new methods, or would we implement a new type with different method implementations?
I'd vote for changing the current concat implementation to the first-rejection variant, like your code snippet above.
I've just pushed pacta 0.2.0 which should have this first-rejection behaviour in it. Please give it a whirl and let me know if that helps.
As raised by @evilhackerdude in https://twitter.com/evilhackerdude/status/345660120874758145, should concatenating promises cause the resulting promise to inherit the state of the original promises (e.g. should a rejection in one of the promises cause the new promise to be rejected)?