Programming usually happens in the context of a business, and the technology used has implications in a cost/benefit analysis.
Being able to express invariants at the type level is cheaper for a business at scale.
If you consider this huge overhead in development cost, maybe time is better spent in less intrusive ways of improving software reliability.
My impression is that advanced type systems interest people because they're cool moreso than because they're practical tools for reducing errors.
The kind of discussion I see on this post generally reinforces my impression.
FWIW, I'm not suggesting moving everything possible into types. I'm suggesting types are better than not having them, just like tests are better than not having them.
I don't know, maybe there is a good way of structuring the software to avoid this effect (I'm not extremely invested in type systems), but maybe it's just a lot of additional pain on top -- too much perceived pain for people who can barely make their software "seems to work".
And if I then look at the actual data transformations behind all this code: It would be a 2 day exercise in Clojure to re-build this from scratch.
firstly, the most available `head` function crashes on half the constructors.
more fundamentally, just try using any file or network io method. you just won't have a clue how it can fail, because it isn't even documented.
there's many methods where the best you can do is work out what exception is being used to wrap a C errno and read the appropriate Linux man page.
at least C documents it's functions that can return errors, and usually encodes them in the type. in Haskell, it's just, "if you're dumb enough to use IO (and what alternative have you got), anything can crash all the time. deal with it".
Haskell is great right up to that point, but that's a critical point.
(I've tried to find ways to deal with this, but the most people seen to refer too something else when discussing how horrible exceptions are, so I wonder if I'm insane)
I suggest you come to https://www.reddit.com/r/haskell/ if you'd like more discussion about it. We often have threads wishing for partial functions to be removed from base!
it won't let me know how or if the function you wrote will throw an exception, or what kind of exception it will throw, unless it's documented in the type.
but my objection is that many times, the possibly of failure is only present in my generic, language/api agnostic knowledge that a file might not be readable or a ship might drop an anchor on a cable. having thought about it, I then have to read the source code to understand what exception might get thrown, so I can prevent my program from crashing.
(i would prefer it to continue as best as it can in the case that some api is unavailable, which is obviously a usecase dependent decision)
This is more effective than trying to remember to always check the head function in every single place you ever try to get the first element of a list.
Yes, you can still write a compiling but wrong program. But it will likely be pretty close to what you actually want it to do, and it's easier to notice the behavior is not what you expected in one place, enforce that behavior via types, and see where you went wrong through compiler errors.