4 ms·
So much wrong in one place. A promise is the IO monad, with `then` being `>>=` [1]. If you write your promises code not to cause explicit side effects - it won
by inglor 11y ago
So much wrong in one place. A promise is the IO monad, with `then` being `>>=` [1].
If you write your promises code not to cause explicit side effects - it won't and you get pure code.
The fact you have (controlled!) side effects is the whole purpose of the IO monad. You can't avoid side effects or your program wouldn't do anything, a promise keeps the side effects in a box (the promise) and lets you code using boxes so that your code is purer. Of course, not all your code can be _actually_ pure because all code needs side effects.
The FUD about async/await is even stranger. JS _has_ async/await, it already shipped in Microsoft Edge (IE) and it's coming to other browsers. It is based on promises (just like it's based on Tasks = Promises) in C#.
The fact people talk so much about this without learning the topic is amazing. I'm genuinely disappointed with the quality of discussion in HN over these topics lately.
Monet is also a bad implementation of the IO monad in JS, in fact it's not an implementation at all. Here is an issue I opened there a while ago: https://github.com/cwmyers/monet.js/issues/25 https://github.com/cwmyers/monet.js/issues/25
[1] up to the fact `.then` does both `fmap` and `>>=` through overloading based on the return type. Seriously, if you remove the exceptions and the fact you can return an unwrapped value it's `Promise a -> a -> Promise b -> Promise b` for then's signature (the Promise a being `this`, the a -> Promise b` being the handler and the return value being itself).
- asQuirreL 11y agoNot sure promises are equivalent to the IO monad in particular. They could form a Monad instance, although that is not the interface they have chosen to expose. It does seem it would be more similar to the `Either` monad, however.
- inglor 11y agoThe type signature, with `catch` is something like Either mixed with `IO`, it's just a specific form of continuation[1]. Promises are not _exactly_ like an IO monad because it would not be pragmatic, but it serves the same purpose (controlled side effects and boxing temporal state) in the same way (a bind operator). If you look at all the examples online for `IO` [2] they all translate 1-1 to promises just fine :) [1] : http://blog.sigfpe.com/2008/12/mother-of-all-monads.html http://blog.sigfpe.com/2008/12/mother-of-all-monads.html [2] : for example http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html http://adit.io/posts/2013-04-17-functors,_applicatives,_and_...
- asQuirreL 11y agoOh yeah, I totally agree, the examples for the IO monad match up very well to what can be done with Promises. My point was more that this is the case because the IO monad is the canonical black box monad: All you can do with it stems from its implementation of the monad interface, and so anything that behaves like a Monad will look very similar. This is tantamount to saying that Promises have a potentially useful Monad instance (which I am completely in agreement with you on). The point about continuations is also a very interesting one, but I think again, stems from the same idea: Almost any monadic interface can be simulated with continuations.
- tel 11y agoPromises also have a notion of parallel tasking which isn't, at least in my mental model of IO, really IO. But of course we're talking about IO... so my mental model is just that: mine and mine alone, really.
- Peaker 11y ago`Promise a -> (a -> Promise b) -> Promise b` is missing some parenthesis.
- dangoor 11y ago> If you write your promises code not to cause explicit side effects - it won't and you get pure code. The way I've seen promises used in JS is always in this pseudocode form: - initiate something side effecty (making an HTTP request, for example) - resolve the promise once the value is ready Is there something you have in mind for how we'd write promises-based code without side effects in JS?
- inglor 11y agoThe same way you'd write "code that doesn't cause side effects" in Haskell. You cause side effects. The thing is with promises (like IO) the side effects are limited to a box you can open, process and close. So given the same input the same function will always return the same output. If you have a function that asynchronously computes a random number - it won't return different numbers and will always return a promise for a random number. It will never be observable that being called with a different input it produced a different output (as long as you don't mutate global state or anything like that). In Haskell, IO is implemented in a way that causes side effects at the platform level. If there are no side effects there is nothing going on and the program is a no op after all :) Monads like IO are about _limiting_ side effects and _controlling_ state. In Haskell, the lack of side effects is by the fact IO is provided by the platform. There is no fundamental difference between Haskell's `getLine` and the DOM's `fetch`, both return a boxed value.
- dangoor 11y agoThanks for the followup! > In Haskell, the lack of side effects is by the fact IO is provided by the platform. There is no fundamental difference between Haskell's `getLine` and the DOM's `fetch`, both return a boxed value. In his talk about "effects"[1], Chris Armstrong also talked about making testing easier in Haskell, though I paid less attention to that part, to be honest. `fetch` returns a promise, but calling fetch causes the side effect to occur immediately. I don't know if that's how `getLine` works in Haskell. If I want to test code that calls `fetch` without an HTTP request actually hitting the network, I need to put in a mock `fetch`.[2] Or, if there was another return type that put the side effect in a box that the platform handles later (or not at all, in the case of a test), that seems like a win. [1]: https://www.youtube.com/watch?v=D37dc9EoFus https://www.youtube.com/watch?v=D37dc9EoFus [2]: another option, pointed out on Twitter, is that a promise (either from the fetch or from the test) could be passed in to the code under test. That seems less pleasant but requires no new machinery.