5 ms·
Monads are pervasive: async-await. We just don’t call them monads.
by acchow 2y ago
Monads are pervasive: async-await.
We just don’t call them monads.
- bazoom42 2y agoHow is async-await monads? Isn’t it just syntax sugar over callbacks?
- ryandv 2y agoConsider async-await a syntactic sugar over Promises (from JavaScript). Then, Promises constitute an instance of the Monad typeclass where monadic `bind` or (>>=) is `Promise.then()`, and `return` is `Promise::resolve()`. Here is a translation of a modification of the example given in [1]: const promise1 = Promise.resolve(123); promise1.then(v => v * 2).then((value) => { console.log(value); // Expected output: 246 }); into Haskell: ghci> let promise1 :: IO Int = return 123 ghci> promise1 >>= (return . (* 2)) >>= print 246 One key discrepancy worth pointing out is that in the `Promise.then()` API of JavaScript, the function provided to `then` (e.g. `v => v * 2` above) is implicitly composed with a call to `::resolve` in order to turn that function's pure return value, the `Number` 246, into a Promise resolving into the `Number` 246; in Haskell, this operation must be made explicit (hence the composed function `return . (* 2)` passed to the first application of (>>=) or `bind`). You could say that the instance method `Promise.then()` expects an argument of type (a -> b), with the return value of type `b` being implicitly and automatically wrapped into a Monad `m b`, whereas Haskell's bind expects an argument of type (a -> m b) on that operator's right-hand side, with the return value explicitly wrapped into a Monad `m b` by the provided function argument itself. [0] https://wiki.haskell.org/Monad https://wiki.haskell.org/Monad [1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- bazoom42 2y agoMaybe I’m confused, but I dont see how Promise.then() corresponds to bind? If I understand correctly, the point of the bind function is you pass a callback which itself return the monad type. But the Promise.then() callback should not return a monad but just the regular result value of invoking the callback. So in essence Promise.then() is like Array.map() while bind is like Array.flatMap() Edit: It seems you are correct, you can indeed return a promise in the callback and it compose correctly. But in your example the callback does not return a promise and is therefore not an example of monadic bind.
- ryandv 2y agoI had a caveat in my original post re. the implicit wrapping of the `Promise.then()` callback's (pure) return value in a new Promise, and how this differs from Haskell's monadic bind; I had hoped to make a loose analogy while pointing out the differences for the sake of illustration. However it is indeed also possible to return a Promise from `.then()`'s callback, which is closer to Haskell's bind: [0] The behavior of the returned promise (call it p) depends on the handler's execution result, following a specific set of rules. If the handler function: * returns a value: p gets fulfilled with the returned value as its value. [...] * returns an already fulfilled promise: p gets fulfilled with that promise's value as its value. ... then you can obtain a solution closer to the Haskell translation by using the behaviour of the second cited bullet point from the MDN article: const promise1 = Promise.resolve(123); promise1.then(v => Promise.resolve(v * 2)).then((value) => { console.log(value); // Expected output: 246 }); [0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- bazoom42 2y agoThis article argues that while promises support the required operations for monad, they do not support the monad laws: https://www.siawyoung.com/promises-are-almost-monads/ https://www.siawyoung.com/promises-are-almost-monads/
- ryandv 2y agoIt's a good point. `Promise::resolve()` "flattens nested layers of promise-like objects (e.g. a promise that fulfills to a promise that fulfills to something) into a single layer." [0] The example was meant to be more of an illustrative analogy than an exact correspondence. [0] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/resolve https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...
- deleted 2y ago[deleted]
- wk_end 2y agoAt that moment, the student became enlightened.
- bazoom42 2y agoCallbacks are not the same as monads if that is what you are implying.
- mrkeen 2y agoThat's right, but only because it's a 1-to-many comparison error. Callbacks are one particular monad, not monads in general: https://jsdw.me/posts/haskell-cont-monad/ https://jsdw.me/posts/haskell-cont-monad/
- dumbo-octopus 2y agoBut then CPS machinery is often used to implement Monads. > Programming with monads strongly reminiscent of continuation—passing style (CPS), and this paper explores the relationship between the two. In a sense they are equivalent: CPS arises as a special case of a monad, and any monad may be embedded in CPS by changing the answer type. https://cs.uwaterloo.ca/~david/cs442/monads.pdf https://cs.uwaterloo.ca/~david/cs442/monads.pdf
- bazoom42 2y agoPromises in JavaScript are not monads as far as I can tell. While they have a somewhat similar interface, they do not appear to obey the monad laws.
- explaininjs 2y agoThere is one particular edge case in which they do not satisfy the laws. That happens to make them much more practical in day to day coding than a strict interpretation would be.
- bazoom42 2y ago
- vilunov 2y agoAsync-await in Rust isn't a Monad.