I have defined a custom Either type and have functions returning a Promise(Either(left,right)). To allow for chaining such functions I modified Promise's prototype like so:
Promise.prototype.andThenE = function(andThen) {
return this.then(p => {
return p.fold(
e => Promise.reject(Either.left(e)),
s => andThen(s),
);
}).catch(c => c);
};
This allowed me to write code like:
const response = await functionXReturningPromiseEither(input).andThenE(functionYReturningPromiseEither).andThenE(...);
I'm aware that extending native objects' prototypes is bad practice and I'm trying to yank this andThenE and put it directly on my Either and am unable to get it to work/chain correctly.
Here's my simple implementation of Either:
const Either = {};
Either.fromPromise = promise => {
return promise.then(Either.right, Either.left);
};
Either.left = Either.failure = x => ({
map: f => Either.left(x), //no-op: no mapping if "left" value
fold: (l, r) => l(x), //apply "left" function to extract error value
andThen: f => Either.left(x), //or flatMap or chain or join: Left(Left(x)) -> Left(x)
dump: () => x, //for debugging
});
Either.right = Either.success = x => ({
map: f => Either.right(f(x)), //map only if "right"
fold: (l, r) => r(x), //apply "right" function to extract success value
andThen: f => f(x), //or flatMap or chain or join: Right(Right(x)) -> Right(x)
dump: () => x, //for debugging
});
If I do this it works flawlessly:
const f = async (arr) => Either.right(arr.map(x => x+1));
const res = await Either.fromPromise(Promise.resolve([1])).andThenE(f).andThenE(f);
console.log(res.dump()); //[3] - is of type Either.right([3])
However, I am unable to get andThenE to become a member of the Either in any meaningful way.
I tried doing this to no avail:
PromiseEither = promise => ({
andThenE: f => {
return PromiseEither(promise.then(p => {
console.log("inside promise");
return p.fold(
e => Promise.reject(Either.left(e)),
s => s.andThen(f),
);
}).catch(c => c));
},
});
Either.fromPromise = promise => {
PromiseEither(promise.then(Either.right, Either.left))
}
This doesn't succeed:
const res = await Either.fromPromise(Promise.resolve([1])).andThenE(f).andThenE(f);
console.log(res); //prints PromiseEither's structure and await is meaningless
I've tried many other variations to know avail. I thought it was straightforward but after hours of banging my head, I haven't made any progress. What may I be missing? Is this even possible?