3 ms·
Async is equivalent to the io monad. It is in itself a monad, I know, but I’m saying it’s just like the io monad. It pollutes everything it touches. It’s litera
by ninetyninenine 2y ago
Async is equivalent to the io monad. It is in itself a monad, I know, but I’m saying it’s just like the io monad. It pollutes everything it touches. It’s literally only effective when paired with IO. So it’s actually in many ways identical.
And that’s a good thing.
In attempting to avoid the pollution u end up implementing the imperative shell/functional core pattern.
Most programmers don’t know that pattern. But for those in the know, the pollution is a good thing.
If you programmed in Haskell you know what’s up. The way you avoid the io monad from polluting everything is part of what makes the program so modular. Async does the same thing. Literally.
await b(await a())
The above is roughly equivalent to this in haskell:
a >>= b
How do you avoid pollution? The answer to this question makes your program better.
- gpderetta 2y agoHaskell has significantly more powerful abstraction capabilities than your average async/await language though, making coloring less of a problem. Also in Haskell you can only perform IO (aside from unsafe IO I guess) inside the IO monad, potentially making the abstraction worthwhile, this is not the case in many other languages.
- ninetyninenine 2y agoIt’s the same in typescript if your io is exclusively always called from async functions.
- jmillikin 2y ago"X is just a monad" isn't a useful statement, because lots of types are monads (e.g. lists, hash maps, and nullable pointers). An important difference between async/await and Haskell's `IO a` is that it's possible for asynchronous code to invoke sync code, and in some languages (such as Rust) vice-versa. So it acts more like a monad transformer, providing operations `IO a -> AsyncIO a` and `AsyncIO a -> IO a`. The main challenge of async/await is that unskilled people who don't understand threads try to use async/await as a substitute, which leads to bizarre articles like "what color are your functions".
- ninetyninenine 2y agoI said async functions can be treated as the IO monad. And I also said that I realize that promises are themselves monads but that wasn’t my point. The point was to use async functions as coloring in the same way Haskell does it with the IO monad.
- tromp 2y agoThat's not Haskell AFAIK. Do you mean a >>= b also known as monadic bind of a and b?
- ninetyninenine 2y agoYeah typo. Corrected.
- instig007 2y ago> The above is roughly equivalent to this in haskell: It's not equivalent. > How do you avoid pollution? Haskell has <$> and the infrastructure of HKTs to stop this infectious propagation of IO, other languages do not, and their async/await colors do not isolate side-effectful actions from the rest pure parts of your codebase. https://hackage.haskell.org/package/base-4.20.0.1/docs/Prelude.html#v:-60--36--62- https://hackage.haskell.org/package/base-4.20.0.1/docs/Prelu...
- ninetyninenine 2y agoI said roughly equivalent. Async functions pollute and represent io in the same way the io monad does. The io monad does not isolate io from your pure code. It’s infectious just like an async function. It’s the abstractions and ways to stop the infection that makes the code pure. You don’t even need hkts to do this. Most languages don’t have a type representing this infection. The infection propagates everywhere without anyone realizing it. The IO monad explicitly tells the developer that the infection is occurring. I’m saying that async functions do the same thing as the io monad. The <$> operator in Haskell is just sugar for patterns to stop the pollution from occurring. You can implement it in typescript too. It just won’t be as general as that operator is defined across functors. In typescript you would define a function across only promises.
- instig007 2y ago"Roughly equivalent" isn't equivalent at all. > I’m saying that async functions do the same thing as the io monad. > The <$> operator in Haskell is just sugar for patterns to stop the pollution from occurring. No they don't. Async functions aren't IO actions in Haskell terms, and for the latter argument of <$>, you need referential transparency (via laziness) too, otherwise your attempt at "sugaring" your async functions will break at the first binding expression in a local scope for future processing elsewhere: ... let arg = processData <$> ioAction in ... Do you want to wrap-and-call-later all of these cases into lambdas by hand? :) Show me an example of that being done in a type-safe way in typescript, and I'll point you at the layers that will break composition at the next binding.