4 ms·
> but you can't have a list of Show in Haskell I'm not sure exactly what you mean, but my naive interpretation is that you can: Prelude> :t map show m
by bodhi 11y ago
> but you can't have a list of Show in Haskell
I'm not sure exactly what you mean, but my naive interpretation is that you can:
Prelude> :t map show
map show :: Show a => [a] -> [String]
- dbaupp 11y agoI'm not exactly sure what they mean, since the following works, and is pretty much a drop-in replacement for a Box<...> trait object in Rust. data Showable = forall a. Show a => Showable a This allows for [Showable 1, Showable "foo", Showable 'x'] (It requires the ExistentialQuantification language feature.)
- evanpw 11y agoRight, this is exactly what I meant by setting up the indirection yourself. The main difference seems to be that in Haskell, you have to write this code separately for each typeclass, and wrap/unwrap it manually. In Rust, you just change Show to &Show and you get dynamic dispatch with no extra code. Here's a gist of the two approaches: https://gist.github.com/evanpw/89d89aae1159c608c476 https://gist.github.com/evanpw/89d89aae1159c608c476. One other difference is that in the Haskell showStatic, static dispatch is not a guarantee, just an optimization.
- bodhi 11y agoThis works on single instances, but I'm trying to see how it plays out with lists of `Bar`. As far as I can see, you need to use `Box`: https://play.rust-lang.org/?code=struct%20Foo%3B%0Astruct%20Baz%3B%0A%20%0Atrait%20Bar%20%7B%0A%20%20%20%20fn%20baz(%26self)%20-%3E%20i64%3B%0A%7D%0A%20%0Aimpl%20Bar%20for%20Foo%20%7B%0A%20%20%20%20fn%20baz(%26self)%20-%3E%20i64%20%7B%2010%20%7D%0A%7D%0A%0Aimpl%20Bar%20for%20Baz%20%7B%0A%20%20%20%20fn%20baz(%26self)%20-%3E%20i64%20%7B%2020%20%7D%0A%7D%0A%20%0Afn%20show_static%3CT%3A%20Bar%3E(t%3A%20%26T)%20-%3E%20String%20%7B%0A%20%20%20%20t.baz().to_string()%0A%7D%0A%20%0Afn%20show_dynamic(t%3A%20%26Bar)%20-%3E%20String%20%7B%0A%20%20%20%20t.baz().to_string()%0A%7D%0A%20%0Afn%20main()%20%7B%0A%20%20%20%20let%20foo%20%3D%20Foo%3B%0A%20%20%20%20let%20baz%20%3D%20Baz%3B%0A%20%20%20%20let%20k%3A%5BBox%3C%26Bar%3E%3B%202%5D%20%3D%20%5BBox%3A%3Anew(%26foo)%2C%20Box%3A%3Anew(%26baz)%5D%3B%0A%20%20%20%20println!(%22%7B%7D%20%7B%7D%22%2C%20show_static(%26foo)%2C%20show_dynamic(%26foo))%3B%0A%7D&version=beta https://play.rust-lang.org/?code=struct%20Foo%3B%0Astruct%20... Which seems to me to be effectively the same as `Barrable` in this case, although it's more generic.
- bodhi 11y ago> As far as I can see, you need to use `Box` Which is exactly what you said in the first place! > So you can have a list of Box<Show> in Rust, but you can't have a list of Show in Haskell. But isn't this comparing two different things? You can't have a list of trait/typeclass in either language (excuse the pseudo-syntax): Rust: [Bar] Haskell: [Bar a => a] But you can (with some extensions in Haskell) have: Rust: [Box<Bar>] Haskell: [Box Bar]
- evanpw 11y agoYou can also have an array of &Bar: http://is.gd/on9Joc http://is.gd/on9Joc. The difference between &Bar and Box<Bar> is that the latter is an "owned" pointer, and the former is a "borrowed" pointer. (By the way, I love that Rust playpen you linked to. Thanks!) The original comment I replied to said that trait objects (e.g., &Bar) are implemented in the same way as typeclass instances. At first glance, that seems true: both pass around a vtable and determine which function to call at runtime. However, Rust attaches the vtable to the trait object pointer itself, while Haskell passes the vtable (method dictionary) around as a hidden argument. That seems like a trivial implementation detail, but it has an effect on the language: in Rust you can create a list of trait objects, while in Haskell, you can't have a list of typeclass instances. It's true that you can emulate the Rust implementation in Haskell: under the hood, the existentially quantified Barrable contains a pointer to an instance of Bar as well as the dictionary of Bar methods, exactly like Rust's fat pointer representation of a trait object. But since the rest of the language expects method dictionaries to be passed as separate arguments, you have to wrap and unwrap values of type Barrable in order to use them. This is a great example of how implementation choices influence language design, which is a topic I find really fascinating.
- twic 11y agoThat takes a list of a, where a is some type which is Show. You can't have a grab-bag of different Show things in there.
- kimundi 11y agoThat's not a list of Show, that's a list of a single type that instantiates Show. The difference being that in your code you can only put in a single type at a time, eg [Int] or [String], but not both Int and String under the common Show interface type.
- bodhi 11y agoAha, thanks (to twic also). Now I get it!