4 ms·
Haskell's actual problem isn't the lack of a comprehensive standard library, but rather the presence of core language features that actively hinder large-scale
by catnaroek 10y ago
Haskell's actual problem isn't the lack of a comprehensive standard library, but rather the presence of core language features that actively hinder large-scale modular programming. Type classes, type families, orphan instances and flexible instances all conspire to make as difficult as possible to determine whether two modules can be safely linked. Making things worse, whenever two alternatives are available for achieving roughly the same thing (say, type families and functional dependencies), the Haskell community consistently picks the worse one (in this case, type families, because, you know, why not punch a big hole on parametricity and free theorems?).
Thanks to GHC's extensions, Haskell has become a ridiculously powerful language in exactly the same way C++ has: by sacrificing elegance. The principled approach would've been to admit that, while type classes are good for a few use cases, (say, overloading numeric literals, string literals and sequences), they have unacceptable limitations as a large-scale program structuring construct. And instead use an ML-style module system for that purpose. But it's already too late to do that.
- tibbe 10y agoThere can be more than one problem, including having a small standard library.
- catnaroek 10y agoThe lack of a standard library can be fixed relatively easily: write libraries! OTOH, the existence of anti-modular language features that are extensively used in several major libraries, is a more serious problem, because: (0) It means that libraries in general won't play nicely with each other, unless they're explicitly designed to do so. (1) It can't be fixed without throwing away code.
- tibbe 10y agoThis whole thread is exactly about how "write libraries!" (if done outside the standard library) doesn't work (see my top post). I do agree that lack of modularity features certainly doesn't help though.
- wyager 10y agoHow are type families worse than fundeps? That's a pretty ridiculous assertion; the things you can do with fundeps are strictly fewer than the things you can do with type families. > The principled approach You're dead wrong. The principled approach here is dependent types and full-featured type-level functions. Fundeps are a hack that let you implement a small subset of such functions (while type families gets us a bit closer to the ideal). > they have unacceptable limitations as a large-scale program structuring construct. Such as? > And instead use an ML-style module system for that purpose. How about we just use C macros for parametricity? ML-style modules have their uses, but they aren't nearly as elegant as a clean type-level solution.
- catnaroek 10y ago> How are type families worse than fundeps? That's a pretty ridiculous assertion; the things you can do with fundeps are strictly fewer than the things you can do with type families. It's not about how much you can do (otherwise, just use a dynamic language, you can do everything, even shoot yourself in the foot!), it's about whether the result makes sense, and how much effort it takes to make sense of it. > You're dead wrong. The principled approach here is dependent types and full-featured type-level functions. Fundeps are a hack that let you implement a small subset of such functions (while type families gets us a bit closer to the ideal). You wanna play the dependent type theory card? Type families as provided in Haskell are incompatible with univalence. type instance Foo Bool = Int type instance Foo YesNo = String Please kindly provide the isomorphism between `Int` and `String`. Case analysis only makes sense when performed on the cases of an inductive type, which the kind of all types is not. > Such as? The insistence on globally unique instances? > How about we just use C macros for parametricity? What does this even mean? > ML-style modules have their uses, but they aren't nearly as elegant as a clean type-level solution. See here for how modular type classes, as proposed for ML, would actually prevent the issues caused by Haskell-style type classes: http://blog.ezyang.com/2014/09/open-type-families-are-not-modular/#comment-20939 http://blog.ezyang.com/2014/09/open-type-families-are-not-mo...
- wyager 10y ago> otherwise, just use a dynamic language, you can do everything, even shoot yourself in the foot! Type classes allow huge flexibility while maintaining type safety, to a much greater degree than fundeps allow. > it's about whether the result makes sense Which they do. Perhaps you have some examples of when type families confused you or made you perform an error? > Type families as provided in Haskell are incompatible with univalence. TFs aren't dependent types. However, they are on the right track. Fundeps are farther away from the right idea. Could you explain to me what's wrong with your example? I'm not up to date on HoTT, but it seems like there's nothing in principle wrong with pattern matching on elements of *. That seems like an important feature of type-level functions. >The insistence on global unique instances? Why is this a problem? It makes sense from a theoretical perspective (we don't associate multiple ordering properties with the things we call "the integers"), and it's very easy to use newtype wrappers to create new instances if needed. > What does this even mean? ML modules are flexible, but backwards from a theoretical perspective. Parametricity is something that should be embedded in the type system, not the module system. > See here Interesting example. However, I doubt that the syntactic cost of using such a system is less than the syntactic cost of enforcing global instance uniqueness and using newtype wrappers.