Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

It's not quite a Promise.

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).



Obviously, not all railways are like Promises (they don't need to be async) but Promises are kind of railways, as the parent commenter said.

Not sure what you mean by "recursively build up and tear down" but this JS snippet sure looks a lot like the F# one in the slides

  const updateCustomerWithErrorHandling = (...args) =>
    receiveRequest(...args)
      .then(validateRequest)
      .then(canonicalizeEmail)
      .then(updateDbFromRequest)
      .then(sendEmail)
      .then(handleSuccess, handleError)
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.


Promises don't have to be around either.


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.


Promises are functors not monads because they map (.then) but the return value becomes the new promise. The chain is flat

Rxjs streams are monads because you can map a stream to a stream which wraps the inner stream in a source stream, which you can then flatMap.


> Promises are functors not monads

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.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: