7 ms·
I don't have time to write a whole essay, so let me just establish my credentials: - I wrote the generic associated types RFC (how Rust will implement higher k
by withoutboats 8y ago
I don't have time to write a whole essay, so let me just establish my credentials:
- I wrote the generic associated types RFC (how Rust will implement higher kinded polymorphism).
- I wrote the const generics RFC (the closest Rust will get to dependent types).
- I wrote the async/await RFC, as well as the linked blog post.
That is to say that I am intimately familiar with how Rust's type system can be extended to support more "powerful" abstractions.
Monads as implemented in pure functional programming languages like Haskell cannot usefully abstract over asynchronous and synchronous IO in Rust for a variety of reasons having to do with the way the type system exposes low level details by virtue of Rust being a systems programming language. I do not believe that `do` notation could be a useful mechanism for achieving either the ergonomics or the performance that async/await syntax will have in Rust.
I'm responding to you because you're the top comment, but I could write a similar response to a lot of comments here. Monads, stackful coroutines, green threads, CSP, etc - we've heard of them! :) We have well-motivated reasons to choose async/await: its the only solution that meets our requirements.
- nazka 8y agoOut of topic. Wow withoutboats you didn't have an account here before? Welcome! That's great to see you coming here and to see you giving many in-depth and very precise answers.
- canndrew2016 8y ago> Monads as implemented in pure functional programming languages like Haskell cannot usefully abstract over asynchronous and synchronous IO in Rust for a variety of reasons having to do with the way the type system exposes low level details by virtue of Rust being a systems programming language. I do not believe that `do` notation could be a useful mechanism for achieving either the ergonomics or the performance that async/await syntax will have in Rust. Sorry, but I don't buy it. I had a half-baked, unfinished proposal for an effects system that would have allowed Rust to implement async/await just as efficiently (no stackful coroutines) along with any number of other effects [0]. Maybe it wouldn't have been a good idea due to stretching Rust's complexity budget too far, but that's very different from saying it's impossible. Having watched the development of Rust closely I really think that the design team just didn't understand the theory side well enough to be able explore the design space here. (I'm not being as critical as I might sound, PL theory is hard and the Rust devs have wielded it much more competently than the designers of any other non-research language). [0] https://internals.rust-lang.org/t/start-of-an-effects-system-rfc-for-async-etc-is-there-any-interest-in-this/7215 https://internals.rust-lang.org/t/start-of-an-effects-system...
- withoutboats 8y agoThe first part of your comment is unresponsive to mine; the last part is pretty rude & factually wrong (we are not motivated to implement an effect system right now; we understand the theory). Sticking to the first part: an effect system is not what the user I was responded to was talking about. They were talking about building do notation on top of type classes with higher kinded polymorphism, which cannot effectively abstract over the monadic operations in Rust.
- canndrew2016 8y ago> The first part of your comment is unresponsive to mine; I interpreted OP's comment as complaining about the lack of more general abstractions in Rust that would allow you to implement async/await. Your comment specifically mentioned Haskell-style monads (eg. a `Monad` trait), but that's not the only way to implement something like this. > the last part is offensive & wrong Quoting steveklabnik: > it’s an open research problem if do notation can work in Rust. Until that’s solved at all, we’re just not sure it’s possible. ... "Open question" doesn't mean "impossible", mind you. But nobody has ever come up with a design. In the meantime, we have users to support... Isn't this what I was saying? "We don't know how to do it, so we're going with the easier option." Edit: To be clear, I don't think async/await we've ended up with is necessarily in the wrong direction. But I also don't think that "we thoroughly explored the design space of do/monads/effects and concluded that they were impossible to implement ergonomically/efficiently" is really true.
- Manishearth 8y ago"impossible" is a highly contextual term here. Adding this to Rust isn't "impossible", of course it isn't. We can "just" slowly turn Rust into Haskell using the edition mechanism. Done. When folks say something is "impossible" in such a context, they mean "given the constraints", which include goals the lang team has for the language. An effects system is pretty heavyweight and may violate these goals.
- withoutboats 8y ago
- lapinot 8y agoDidn't mean to bash the lang design team at all, actually i was kinda hoping for you folks to reply interesting and tricky stuff about how things are not so simple. This is probably only because you didn't develop the answer fully but i still struggle to see how monads (or other structures in that family) couldn't apply here: they aren't implemented in any way and just provide interface (eg not caring about rust at all, the semantic of that feature here is very monadic, it should mostly behave like the CPS monad). Anyway, i'm gonna stop arguing, look at how it is/will be implemented and hopefully wait for that essay of yours, to have a broader picture.
- withoutboats 8y agoHere are three problems: Higher kinded polymorphism results in trivially undecidable type inferences without something like currying; the restrictions needed to support it would be arbitrary and weird given that Rust does not have currying (essentially some rules to reconstruct the restrictions of currying in type operator context). Instances of both Future and Iterator do not implement the Monad type class as defined in Haskell, because the "fmap" operator does not return the "self" type parameterized by a new type, it returns it own new type. This is because the state machine they represent is leaked through their function signature. Do notation doesn't work with the imperative control flow that Rust has, which other people have already discussed.
- runT1ME 8y agoYou don't need HKTs to implement 'do' notation. A good example is LINQ query syntax from C#! You actually have full blown monadic comprehension that you can use to easily write 'flattened' (ie, no async pyramid of doom) Future/Promise code with.
- snuxoll 8y agoA better example would be computation expressions in F#, the async {} and query {} builders are super easy to work with and don't rely on HKT's to work (since there's no such thing in .Net). I think such a design would work pretty well in rust, and doesn't require adding a bunch of single-purpose keywords - something I wish the C#/.Net team did considering F# had async first.
- fmap 8y agoHave you considered algebraic effects and handlers? If you add a linearity restriction on the return continuations (easily doable with the existing type system of Rust) their implementation is no harder than async/await, yet they can express many useful monadic abstractions. ...I saw this thread too late, hopefully you will still see this comment. I'm genuinely curious.
- steveklabnik 8y agoThere's a sibling subthread about this. https://news.ycombinator.com/item?id=17538191 https://news.ycombinator.com/item?id=17538191