It helps if you can express these preconditions in the first place, though.
It helps if you can express these preconditions in the first place, though.
That said, Rust is just enough Haskell to be all the Haskell any systems programmer ever needed, always in strict mode, with great platform support, a stellar toolkit, great governance, a thriving ecosystem and hype.
Lots of overlap in communities (more Haskell -> Rust than the other way IMO) and it's not a surprise :)
I think an IO monad and linear types [1] would do a lot for me in a Rust-like
[1] Affine types? Linear types? The ones where the compiler does not insert a destructor but requires you to consume every non-POD value. As someone with no understanding of language theory, I think this would simplify error handling and the async Drop problem
One large problem with Haskell that pushes people to Rust is strictness, I think -- laziness is a feature of Haskell and is basically the opposite direction from where Rust shines (and what one would want out of a systems language). It's an amazing feature, but it makes writing performant code more difficult than it has to be. There are ways around it, but they're somewhat painful.
Oh there's also the interesting problem of bottom types and unsafety in the std library. This is a HUGE cause of consternation in Haskell, and the ecosystem suffers from it (some people want to burn it all down and do it "right", some want stability) -- Rust basically benefited from starting later, and just making tons of correct decisions the first time (and doing all the big changes before 1.0).
That said, Haskell's runtime system is great, and it's threading + concurrency models are excellent. They're just not as efficient as Rust's (obviously) -- the idea of zero cost abstractions is another really amazing feature.
> [1] Affine types? Linear types? The ones where the compiler does not insert a destructor but requires you to consume every non-POD value. As someone with no understanding of language theory, I think this would simplify error handling and the async Drop problem
Yeah, the problem is that Affine types and Linear types are actually not the same thing. Wiki is pretty good here (I assume you meant to link to this):
https://en.wikipedia.org/wiki/Substructural_type_system
Affine is a weakening of Linear types, but the bigger problem here is that Haskell has a runtime system -- it just lives in a different solution-world from Rust.
For rust, Affine types are just a part of the way they handle aliasing and enable a GC-free language. Haskell has the feature almost... because it's cool/powerful. Yes, it's certainly useful in Haskell, but Haskell just doesn't seem as focused on such a specific goal, which makes sense because it's a very research driven language. It has the best types (and is the most widely adopted ML lang IIRC) because it focuses on being correct and powerful, but the ties to the ties to practicality are not necessarily the first or second thought.
It's really something that Rust was able to add something that was novel and useful that Haskell didn't have -- obvious huge credit to the people involved in Rust over the years and the voices in the ecosystem.
There's actually two different ways that Rust types can always be discarded: mem::forget and mem::drop. Making mem::forget unsafe for some types would be very useful, but difficult to implement without breaking existing code [1].
Btw, you are correct with linear types - Affine types allow discarding (like Rust already does).
haskell implements the "perfect derive" behaviour that the blog post is complaining about rust's lack of. the constraint is only propagated to the field types when using a haskell derive, not the parameters themselves (as in rust)
so the following compiles just fine:
data Foo -- not Eq
data Bar a = Bar
deriving Eq
f :: Eq (Bar Foo) => ()
f = ()
* creating type &T or &mut T is forbidden; therefore also applying & and &mut to a value of linear type, or using ref and ref mut at the top level of patterns that match a value with linear type
* field access is forbidden, except through pattern matching (either match or let) because pattern matching consumes the matched value
* implementing Copy or Drop is not allowed (Copy makes no sense, with Drop using destructuring patterns would not be possible). Well, Drop would not be implementable anyway, together with many other traits, because it takes &mut self (which is not creatable).
I would have no idea how to express it in the syntax.