4 ms·
I'm surprised there's not a single mention of JavaScript promises in the post. This is basically what they are, and their syntax naturally imposes this techniqu
by chatmasta 8y ago
I'm surprised there's not a single mention of JavaScript promises in the post. This is basically what they are, and their syntax naturally imposes this technique as a solution to most use-cases.
Here [0] is an example of how I've used this technique in functional JavaScript code. Please don't judge too hard as this was my first JS library 2+ years ago... certainly lots of problems in there (although it has been running untouched in production since then!)
[0] https://github.com/milesrichardson/kewt.js/blob/master/kewt.js#L326 https://github.com/milesrichardson/kewt.js/blob/master/kewt....
- zaarn 8y agoIt'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).
- chatmasta 8y agoNot 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.
- joshribakoff 8y agoPromises 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.
- matt_kantor 8y ago> 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.
- vimslayer 8y agoObviously, 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.
- ghthor 8y agoPromises don't have to be around either.
- joshribakoff 8y agoEach .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.
- tzahola 8y agoI'm surprised there's not a single mention of Bash in the post, because you know, Bash has functions too... /s
- chatmasta 8y agoI know you're being facetious, but given that Bash functions have return values and also process stdin/stdout, they could be adapted to implement the railroad pattern, yes?
- lmm 8y agoWhat they are is monads - the post just avoids using the term so as not to scare people off. Monads generalise the railway-oriented style between error-handling, async, and many other things. That's their whole point, and that's why they (and functional programming generally) were a big deal years before JavaScript even existed.
- megaman22 8y agoOne thing that is nice about this site in particular, is that it goes out of its way to avoid the kind of FP jargon that confuses the hell out of most people. Sometimes the analogies strain a little bit, but at least for me, it's a thousand times more approachable than descending into math-babble. For example: https://fsharpforfunandprofit.com/posts/monadster/ https://fsharpforfunandprofit.com/posts/monadster/
- chatmasta 8y agoI find the "FP jargon" and "math-babble" to be annoying, but not nearly annoying as the sort of infantilization sites like this engage in. It's a common trope to "dumb down" complex topics into cartoonish explanations, but in reality it only makes the content more confusing, while simultaneously insulting its readers by treating them like children. No, I don't need a "cartoon intro to DNS over HTTP" to understand basic networking concepts. Nor do I need a story about "Dr Frankenfunctor and the Monadster" to understand functional programming concepts. Even when I was a teenager reading about OOP, I didn't want to read about the "Car class inheriting from the Vehicle class" or the "Dog class inheriting from the Animal class." When reading technical content, I always prefer prose that treats its readers as professionals, rather than five-year-olds incapable of understanding complexity without resorting to vacuous and incomplete analogies. The problem is that complex topics are complex. By their very nature they rarely fit into convoluted analogies, and would be better explained by simple use cases and examples.
- Dayshine 8y agoYeah, this website doesn't dumb things down. That page is an exception really. It just deliberately avoids using the common FP words that don't really have any meaning to 99% of programmers. As this huge, detailed, functional programming resource demonstrates, it's perfectly possible to write clear and detailed functional programming guides without that jargon.
- danielrbradley 8y agoIt's not quite the same thing ... the either type is just a simple value which you can think about as just having a boolean saying "is this a successful or unsuccessful result?", and depending on the success attach different data. E.g. a result of parsing JSON from a string would be "successful: true + the parsed object" or "successful: false + the error message". The railway oriented approach is then looking at neat ways of working with these kind of results in the place of try/catch when dealing with errors.
- jorgeleo 8y agoRead the URL: f sharp for fun and profit. I cannot see the reason for featuring javascript in this context.
- airstrike 8y agoFor some reason, javascriptforfunandprofit.com is still unclaimed
- wenc 8y agoJavascript promises are a kind of monad. Douglas Crockford talks about this in his talk "Monads and Gonads" [1] [1] https://www.youtube.com/watch?v=b0EF0VTs9Dc https://www.youtube.com/watch?v=b0EF0VTs9Dc