If something breaks and I need to fix it now, I don't want to be fighting with a language that says, "no-o, no shortcuts, use a proper monad", or takes years to master to that level.
Maybe I'm just missing the point.
If something breaks and I need to fix it now, I don't want to be fighting with a language that says, "no-o, no shortcuts, use a proper monad", or takes years to master to that level.
Maybe I'm just missing the point.
Servant is very complex by itself. It's hard to tell at what scale it pays off. But it gives you more safety than other solutions.
I would love to have the OP on my team, because they have the ambition to build reliable software and I can compromise with them. It's hard to compromise the other way around.
Certainly possible with other languages + frameworks, but I felt really confident relying on it to catch issues due to the strong type guarantees.
First, it is often a sort of humblebrag (as the kids say). I am using this language that is SO advanced that I am a mere intermediate after X years of development. Looks how smart I am for using it. That tends to lead people to dramatically over-estimate how hard it is to become productive in the language.
Second, the emphasis on correctness means that the ecosystem goes to great lengths to explain how all the abstractions work internally and how they are grounded in Category Theory. In other ecosystems (such as Java) they seem to be more focused on talking about the interface and the practicalities of using a library. Spring is extremely complicated but you don't see much ink spilled explaining all the internal implementation details.
Spring is a good example too. I used it quite a bit in my junior years and felt like I would never come to master a framework that is so broad (and that felt over-engineered).
This doesn't mean you cannot be productive using a subset of the language. There's a balance in what you should allow in a codebase being maintained by a team of varied skillset. Maybe Haskell is on the extreme end here, but the other way (like Python, JS, Go) is even worse in my opinion.
I still feel this way. I work on all kinds of weird / cool technologies on the side and I can’t imagine ever coming to call myself in expert on anything because I only use a subset to solve a problem.
I also consider myself intermediate, because I often can't readily grok what are the compiler devs talking about when they discuss e.g. linear types.
I consider myself a Python expert since I can follow PEPs and DSLs with ease.
That doesn't mean that Python is a better language. It does not make the same value proposition.
If something breaks and I need to fix it now, I don't want to be fighting with a language that says, "it's fine to cast that pointer, don't worry about it," or takes years to master to that level.
Maybe I'm just missing the point(er).
You can repeat this argument for any X language you want.
For me you want to work in a language that doesn't let you cut any corners by default. This is what Haskell and some other FP languages do. I can perform unsafe pointer operations in Haskell but it's going to be loud, noisy, and painful to write. As it should be!
In languages like C++/Java/etc you have to be disciplined and opt-in to maintaining the kind of code that Haskell defaults to.
I’m a pretty basic C++er but can use it effectively, if not efficiently. It seems, from the outside, in Haskell you need to know a lot more before even a basic level of effective use is possible.
The effect is pronounced if you're experienced in C++ (and C-like languages in general) and attempt to learn Haskell. There is almost no transferable knowledge from those kinds of languages to Haskell which means you're basically starting from the beginning. That can be infuriating for an experienced developer. It certainly was for me -- twenty-some years of programming knowledge that wasn't terribly useful at all!
When moving from C++ to C# or Rust it's not as big a deal: there are the familiar concepts we can use to bridge the gap towards understanding the missing information.
Haskell is just fundamentally different.
Fortunately though I feel like the "Haskell cliff," is over-stated. The concepts you need to learn to get started and write useful programs is not as high as you might think. The ceiling, like in C++, is really high. Most mainstream languages have, or are planning to add in the next couple of years, all of those features you need when getting started with Haskell: ADTs, pattern matching, parametric and ad-hoc polymorphism, type inference, higher-order functions, and immutable values.
So I think it depends on the code-base you're starting on and what you mean by effective use. If you're trying to contribute to a security analysis tools that uses a lot of type-level programming to encode specification invariants then you'll have a lot of learning to do before you can get started. If you're contributing to a SaaS web application then there's a good chance that only a "basic" level of knowledge about how to program with monads is all that will be required.
They're not so much talking about the language itself, but more about the way thing can be built in it. That's an open-ended problem, since Turing-complete languages let us use any computatable process.
I might consider myself a 'Python expert', since I've used it for over a decade, written code at the CPython level, all the way up to the metaclass level, built many projects, written extensively about the language, critiqued and discussed proposed features, taught it to others, etc.
Yet I wouldn't consider myself an expert in 'the way things can be built with Python'. For example, I can build Python wrappers for native binaries, but that doesn't imply that I'd come up with a design as clever as numpy. I've done a lot of statistical analysis using Python, but that doesn't mean I could come up with a library as elegant as pyro.ai. And so on.
> If something breaks and I need to fix it now, I don't want to be fighting with a language that says, "no-o, no shortcuts, use a proper monad", or takes years to master to that level.
What do you mean? System.IO.Unsafe.unsafePerformIO lets us write impure code; Unsafe.Coerce.unsafeCoerce lets us bypass the type system. Is there something else you'd want to do?