4 ms·
This is very informative, thanks. If you could share some detail on how Rust falls short of Haskell type classes, I'd love to hear it. I'm digging into Rust, bu
by charlieflowers 13y ago
This is very informative, thanks. If you could share some detail on how Rust falls short of Haskell type classes, I'd love to hear it. I'm digging into Rust, but haven't gotten that far yet.
- stream_fusion 13y agoThe Rust trait/typesystem doesn't currently support higher kinded polymorphism.
- adamnemecek 13y agoIt MIGHT in the near future though http://hydrocodedesign.com/2014/04/02/higher-kinded-types/ http://hydrocodedesign.com/2014/04/02/higher-kinded-types/
- dbaupp 13y agos/near//. That article is more "let's describe HKTs in Rust-y terms, so that more Rustaceans understand their purpose" than an actual proposal for implementing them in Rust. Any concrete proposal (i.e. covering implementation details and corner cases, rather than just some syntax/use-cases) would need to go through the RFC process: https://github.com/rust-lang/rfcs/blob/master/active/0001-rfc-process.md https://github.com/rust-lang/rfcs/blob/master/active/0001-rf... ((Unfortunately?) I imagine such an RFC would spend a month or two (or more) being discussed/thought-about.... And double that discussing syntax. ;P )
- jganetsk 13y agoThere are LOTS of things you can do with type classes, and they are super sexy. Let me try to enumerate them. One commenter already noted higher-kinded type classes, which is the basis of Haskell's libraries and do-notation for monads. That's HUGE. But besides higher-kinded type classes, there are others: * Factories and constants in your interfaces. Type classes allow you to put a type variable in the return argument of a method. This lets you put factories and constants in your type classes. For example, if you look at the monoid type class: class Monoid a where mappend: a -> a -> a mzero: a And I can implement this instance Monoid String where mappend x y = AppendStrings x y mzero = "" instance Monoid Integer where mappend x y = x + y mzero = 0 So now I can write generic code where I can get the "zero constant" of a type without knowing what type that is. I could just have a genericMonoid : T where T is a type variable, and all I know about it is that it belongs to class Monoid (maybe it's an integer, maybe it's a string, maybe it's something else). I can now get the zero value of whatever that type is. In fact, my method doesn't have to be dispatched on the type of some input argument. I can dispatch on the return value. Something like multiplyByZero : [Monoid T] int -> T multiplyByZero 0 = mzero multiplyByZero n = mplus mzero (multiplyByZero (n-1)) (Forgive my crappy Haskell pseudo syntax, I haven't written it in a while). Not that multiply by zero is useful. * Operators of greater arity than 1. So I hinted at this above. With "method syntax" arity is always 1. I have one "this". I can operate on it. For all other arguments to my method, I cannot actually constrain them to have the same type as "this". At best, with OOP, my method belongs to some base class, and I can insist that the non-this arguments are of base class type, but I cannot constrain them to have "this" type. This is illustrated in the monoid example above, or in the Eq example I gave, where it can be guaranteed that the two operands to == are always of the same type. In Java, the equals method has to take one argument of type "Object", while the "this" argument has the class's type. * Multiparameter type classes. (This is behind a flag in the Haskell compiler). You can do something like this: class Eating E F where eat :: E -> F -> Meal # E is short for Eater # F is short for Food so now I can type check to make sure that eaters eat the right type of food. instance Carnivore Meat where eat = # specialized implementation for eating meat instance Carnivore Vegetables where eat = # specialized implementation for eating vegetables instance Vegeterian Vegetables where eat = # specialized implementation for vegeterian food
- burntsushi 13y agoI'm not sure if all your examples were meant to be things that Rust doesn't have, but Rust certainly has polymorphic return values. For example, see the `Default` trait: http://static.rust-lang.org/doc/master/std/default/trait.Default.html http://static.rust-lang.org/doc/master/std/default/trait.Def... It's also used to generate random values: http://static.rust-lang.org/doc/master/rand/trait.Rng.html http://static.rust-lang.org/doc/master/rand/trait.Rng.html More generally, Rust supports polymorphism anywhere. e.g., The `Eq` trait: http://static.rust-lang.org/doc/master/std/cmp/trait.Eq.html http://static.rust-lang.org/doc/master/std/cmp/trait.Eq.html AFAIK, >1-arity polymorphism in OOP languages is generally achieved with double dispatch. But it's not as nice (or as easy to understand IMO) as in ad hoc polymorphism. Rust does not have HKT or multi-param traits though.