However, as an actual tool to do actual work, I really don't see why you would go about it for anything but very specific projects.
However, as an actual tool to do actual work, I really don't see why you would go about it for anything but very specific projects.
Well, it’s been paying my wages for the past eight years, so it’s incredibly useful to me. Are we services “very specific projects”? Are data processing systems? Are geospatial data munging? Are financial systems? Those all sound like mundane, every day projects, and they’re exactly what I’ve been working on.
And when it comes to “actual work”, that’s where Haskell truly shines - being able to fearless refactor code and iterate until the compiler is happy again is my favourite feature of Haskell. It’s not the “neat type system”, it’s the ability to not have to keep the entire project in my head at absolutely all times because I might forget to make a stupid change the compiler should have caught for me. The productivity is massive, once you’ve invested the time, but it does take time and it is an investment.
These systems make it easy(er) to model concepts in a mathematical way and this is my natural (or preferred?) mode of thinking. And they enable you to do it easily and ergonomically. What is there not to like?
(I know there are flaws at hand, even some potentially very debilitating flaws depending on your use case. But damn, I'd use these languages wherever I can.)
So in practice, I'll go for a language that allows me to do both easily, instead of going for something like Haskell where any imperative way of doing things is very painful (as well as other issues, of course). So why would I use Haskell and limit myself for fairly marginal benefit?
There is also the saying that Haskell is the world's best imperative language, and that is not without reason, since you can re-use its usual power of abstraction while writing imperative code too.
It's awkward, it has a bad ecosystem, it has just as many issues with hidden state, etc...
The only reason you would want to write imperative Haskell over a modern imperative language is the typesystem, but even that can be an issue sometimes, and I'd risk saying that the Rust or C++ typesystems while being very slightly less expressive are better at scale overall due to their flexibility imo.
Another big one is that it really sucks to debug. Seriously, it's brutally slow compared to what you can do with a good debugger in other languages.
If you care about performance, Haskell can be significantly worse than others, both lower level compiled languages (lazy evaluation, large amounts of trash to be collected by the GC, cache trashing, etc...), and higher level interpreted languages, due to the lack of native accommodations to bind into fast code, or even into GPUs.
There are a lot of disadvantages to Haskell if you're going to do mostly imperative code.
I don’t have time to go into details but nearly every statement you’ve made here is in my opinion wrong, other than the difficulty in debugging (and there are very good reasons why this is difficult).
I’ e never found it hard to write fast Haskell, because I put in the effort to learn how to do it. People forget they also put in the time to learn how to write fast C++, and Java; it’s a very large portion of any software engineering curriculum, it’s literally what algorithms is all about. People find writing fast Haskell hard not because it is fundamentally hard, but because they were never taught how.
> due to the lack of native accommodations to bind into fast code, or even into GPUs.
I have no idea what you mean by this, GHC provides a very good FFI, and there are libraries for binding to Rust, R, Objective-C and others. We also have Accelerate for data processing on GPUs, which includes runtime compilation of native code for both GPUs and CPUs.
Debugging has not been difficult either, but I have always use print debugging in every language, so there is not much I can compare.
Interesting point. What is the purpose of type-declarations? To make implementation easier to understand, I think. When you know (and understand) the type of a component or function you know how to use it, and how to not use it, and thus how to write code that uses it and does what you think it should do.
But if types are harder to understand than the implementation, then types don't help much, do they?
I feel this is largely a lie. The type system is still a crippled language that is also incompatible with the runtime language. It possible to do some very specific things in it, but does it help you describe a system's data flows? Memory allocation patterns? GUI layout engine?
I think the solution is: Just use regular code, it works best. Use types to describe interfaces. Simple types, because with anything else you're painting yourself in a corner.
> It possible to do some very specific things in it, but does it help you describe a system's data flows? Memory allocation patterns? GUI layout engine?
I feel you're underselling quite a bit when you say very specific things, but again, perhaps this depends on the problem domain, your thinking style, your programming style or some other undetermined factor. Out of the things you mention, I would say a definite yes to system's data flows, weaker yes for GUI layout and no to memory allocation patterns, because that is a known weak point.