4 ms·
I... don't actually understand why you would ask that question. How do type classes help, one way or the other, when the discussion is "duck typing cannot (alwa
by nrinaudo 11y ago
I... don't actually understand why you would ask that question. How do type classes help, one way or the other, when the discussion is "duck typing cannot (always) be replaced in static languages by having various types extend a common interface. True or false?".
They allow you do something else, something I would argue is better (and I explicitly said so, "The best solution I know of is type classes, in languages that support them."), but are entirely irrelevant to sanderjd's point and my answer.
- dllthomas 11y agoI know you mentioned type classes (repeatedly and positively). What I mean is that I don't see why, in their presence, there's still a problem. On careful reread, I guess you don't see them as an example of "having various types extend a common interface"? (which would make them a solution, but excluded from the discussion) (edited to add - and I find that description to fit them just find, hence my confusion)
- nrinaudo 11y agoThat's exactly it: they're a good solution to the problem, but since type classes work specifically by avoiding subtype polymorphism (and are instead a mix of parametric and ad hoc polymorphism), they cannot be part of a discussion that is centered on whether or not subtype polymorphism is a good fit. But, yes. The more I code, the more it feels like type classes are never not a good answer.
- dllthomas 11y agoThe thing is, I don't see anything actually restricting the scope of discussion to subtype polymorphism. "The more I code, the more it feels like type classes are never not a good answer." As they are used in Haskell, they sometimes get awkward where you where multiple instances are relevant to the same data in the same scope. You can newtype cast around, but I've been wondering (with multiparameter typeclasses) if reifying the instance we care about is 1) useful, and 2) actually still distinct from explicitly passing the dictionary as a record. Regarding 1, I've consistently leaned "yes", although without tremendous confidence. Regarding 2, I've gone back and forth over time.
- nrinaudo 11y agoAs far as I'm concerned, the discussion I'm referring to started with this comment from realharo: "Usually if you need a bunch of differently-typed objects to fulfill the same contract, you can just make them implement an interface". The way I understood that is, if you have a f(a: A), and need to pass it a B and C, neither of which are subtypes of A, you can just create a new type D, have A, B and C extend D, and modify f to expect a D. My point was that it's not always practical nor even possible to do so. A type class would be a good way to abstract over the type itself and simply require a specific behaviour, but by the time you have f(a: A) where A is a concrete type, and you can't modify f (because it comes from an external library, say), it's too late to retrofit type classes into it. As for your other point - type classes being awkward when you have multiple possible instances for a given type - I agree, but must say that I'm spoiled: my primary use of type classes is with Scala, where they're just, when you come down to it, parameters to functions. You can let the compiler infer them when there is no ambiguity, but when you need to pass an int to a function that expects "A with a monoid", you always have the option of being explicit about which monoid instance to use. I believe Haskell treats them as implicit parameters as well but without the option to pass them explicitly. Finally, I'm afraid you've lost me with your last bit - reifying the instance we care about and passing the dictionary as a record. I wish I had something smart to answer, but I'm not sure I actually understand what it means. I know enough Haskell to be able to be able to read it (a necessary skill if you have even the slightest interest in FP), but not much more than that. Maybe if I knew more I'd have a clearer understanding of what you mean?
- dllthomas 11y agoFleshing out my "other point": "Passing the dictionary as a record" is a pretty common alternative to typeclasses. The way it works is if you have a typeclass: class Foo a where foo :: ... bar :: ... you instead make a record that looks like: data Foo = Foo { foo :: ..., bar :: ... } This works great for a lot of things, and is often preferable to typeclasses when all you're doing is defining an interface. One objection is that things look slightly less tidy, but the main problem with it (where it's a problem at all) is that there's no way of identifying individual implementors of an interface by type anymore. An example where this relevant is Set. We could define the Set operations to take a comparison function, but we couldn't be sure that all comparison functions agree across all interactions with a particular set. What I mean by "reifying the instance" is indexing typeclasses with a (single constructor) type that identifies the instance, and then passing that around to let us select which instance we care about, even for the same underlying type. For example: {-# LANGUAGE FunctionalDependencies #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} import Data.Function (on) class ParamOrd o a | o -> a where pcompare :: o -> a -> a -> Ordering data StringsOverLength = StringsOverLength data StringsLexicographically = StringsLexicographically data IntegersInOrder = IntegersInOrder data IntegersReversed = IntegersReversed data ReversedOrdering r = ReversedOrdering r instance ParamOrd IntegersInOrder Integer where pcompare _ = compare instance ParamOrd (ReversedOrdering r) Integer where pcompare o = flip (pcompare o) instance ParamOrd StringsOverLength String where pcompare _ = compare `on` length instance ParamOrd StringsLexicographically String where pcompare _ = compare Now we could write a new version of Set, `ParamSet o a` such that we can still enforce agreement while choosing our orderings with an argument rather than a newtype.
- deleted 11y ago[deleted]