A promise would be the case in an async functions but railway like presented work in sync functions.
Promises also sorta recursively build up and tear down (IIRC) while railway is a "pass along" situation; each function that generates and error calls the next function with the error where you then simply pass it along (or handle it).
Here, each of the functions can return a result (async or not) or reject with Promise.reject or by throwing. If any of the functions rejects, the rest of the functions in this "happy path" are not called.
Each .then replaces the promise before, instead of wrapping the source promise around it. At each step you have a resolved value, with a monad you'd have to .flatMap because mappining a monad to a monad nests it, which you have to later flatMap to extract the boxed values. Compare rxjs streams which are monads to promises which are functors. monads are functors but not vice versa.
Not sure what you mean by "build up and tear down" but in what way do promises not pass errors to the next function in the chain?
Consider code like this:
p1
.then((value) => {
console.log(value);
return Promise.reject('oh, no!');
})
.catch((e) => {
console.log(e);
// Handle the error if you want, and keep going
return Promise.resolve()
})
.then(() => {
console.log('This still gets executed')
})
How is this not amenable to the railway pattern? You define how you handle the error within a function in the promise chain. Error handlers are fully composable with success handlers, which seems to be the important element necessary for implementing the railway pattern.
That's not quite true. `then` is a weird hybrid of `map` and `bind`. If its callback returns a Promise it acts like `bind` (you don't get a nested Promise), but otherwise it acts like `map`.
And to be pedantic, Promise is neither a functor nor monad because `then` doesn't follow the necessary laws.
A promise would be the case in an async functions but railway like presented work in sync functions.
Promises also sorta recursively build up and tear down (IIRC) while railway is a "pass along" situation; each function that generates and error calls the next function with the error where you then simply pass it along (or handle it).