10 ms·
> An awful lot of energy was wasted memorizing various tricks and conventions to make do with loops, slices and maps where in other languages you'd just call a
by runT1ME 9y ago
> An awful lot of energy was wasted memorizing various tricks and conventions to make do with loops, slices and maps where in other languages you'd just call a generic method.
I feel the same way going from languages with HKTs back to Java/C#...
Not sure why you think they're not as useful, it sounds like you're making the same argument as OP but just moving the bar one notch over...
- mpartel 9y agoI am. I think the OP is fundamentally right about the sweet spot being pretty far from either extreme, I just disagree slightly about where exactly :) Subjectively, I use ordinary generics all the time, but see the need for HKTs only occasionally. It's entirely possible I'm not experienced enough to see most of their possible use cases, but then I'd wager most programmers aren't.
- willtim 9y agoIn retrospect, HKTs are arguably Haskells greatest innovation, enabling extremely general abstractions and huge amounts of code reuse.
- mpartel 9y agoIn my subjective opinion, Haskell has taken abstraction way past the point of diminishing returns, at least for the problems I tend to work on. A large portion of advanced Haskell type system features seem to be about emulating things you could do with side-effects. I guess I prefer Rust's approach to managing side-effects, or even just Scala's implied convention of: use 'var' very sparingly, and mostly locally. Yes, some guarantees get traded away, but so much simplicity is gained. I'm not very experienced with Haskell, but I've written a fair bit of Scala and I've utterly failed to see the value in scalaz and similar libraries, despite trying them a few times. They always seem to add lots of complexity without a tangible benefit. Coming at it from another angle, I just don't see many cases where I feel I have to repeat myself due to a shortcoming of, say, Java's or C#'s type system. If I could add one feature to either, it'd actually be support for variadic type parameters.
- willtim 9y agoAs a counterexample, C# needed expensive language extensions to accommodate both LINQ and Async/await. Both can be implemented in Haskell purely as a library, thanks to HKTs. Both Java and C# tend to rely heavily on frameworks such as Spring to workaround issues with the expressivity of the languages. This causes problems when one needs two frameworks (they don't in general compose). In Haskell, HKTs allow one to write polymorphic programs that are parametric with respect to certain behaviours and dependencies, no dependency injection framework needed. Please don't judge Haskell using Scala and scalaz.
- AndrewBissell 9y agoI'm not sure what Java expressivity problem Spring is meant to solve. XML configs are basically just a duplication of what would be done in a static initializer, except you lose type-checking and get to find your wiring mistakes at startup time instead of compile time. Autowiring annotations can be nice when you first use them, but become inscrutable magic once some other poor sap has to come along and make changes to the original project setup. I just don't understand what is so horrible and inexpressive about a static initialization block. The only possible purpose I see to Spring is if for some reason you really need to be able to change how your dependencies are injected at runtime. (90% of Spring apologists point to this, and 99% of them never use it in practice.) Even then, I don't see how a Spring XML config file (which I have seen run to 4000+ lines, to my horror) is better than just reading some settings out of a properties file to pick an implementation in your static initializer.
- willtim 9y agoI guess passing parameters down manually through all the constructors gets too painful. The language is not expressive enough for a Reader monad! :) Java's static initialiser blocks are too dangerous whenever one has threads.
- mpartel 9y agoNot sure about LINQ, I thought that was "just" syntactic sugar for a bunch of collection methods. Are you refering to extension methods as an unfortunate prerequisite? But I think I get your general point: things like 'Control.Concurrent.Async' ('async'/'await') and 'Control.Monad.Coroutine' ('yield') are libraries that implement some and very generic type classes: 'Functor', 'Applicative', 'Monad'. This then lets you use features that are generic over those type classes ('do' syntax, 'fmap', ...). It's been many years since I had a proper look at Haskell. Maybe it just takes more practice than I had back then to fully "get it". But I still don't see those abstractions being that useful in everyday programming. They seem to have huge potential for hard to follow code as you need to mentally unpack and remember more layers of abstraction, and the gain is not clear to me. Even the features that have trickled down to C# are not _that_ crucial I feel. The way mainstream languages pick the most useful use cases of those abstractions seems pretty OK to me. (Also, macros and compiler plugins are another interesting avenue towards very powerful abstractions, with a different set of problems.) As for Spring and dependency injection, I don't follow how HKTs would help there. Could you give an example? Aren't DI frameworks mostly about looking things up with reflection magic to automate, and arguably just obfuscate, the task of wiring things up in 'main'?
- Merovius 9y ago> I think the OP is fundamentally right about the sweet spot being pretty far from either extreme, I just disagree slightly about where exactly :) And I think an important take-away should be, that this perception is entirely subjective and colored by both of our experiences, preferences and the kinds of problems we work on :)