See, when you are defining a Haskell program, you are conceptually creating a tree of thunks that eventually get executed by the GHC runtime. Those thunks are typed, meaning they have typed inputs and outputs, and are either side-effect-free or are defined in a context that controls their side effects (e.g. the IO monad).
So you can change the definition of types willy-nilly and either get a working compiled program or some error output that tells you exactly what is broken or doesn't make sense to GHC's model of your proposed computation. Because computation itself is typed, you have a stronger guarantee that it will work as expected when executed by the GHC runtime. Because side effects are controlled, you are forced by the type checker to handle runtime errors (or crash).
At least that's how I understand it as someone who works with gifted Haskell engineers, but exists very much on the periphery of understanding.
This is generally true in idiomatic Haskell code, but in fact even pure functions in Haskell can throw runtime exceptions, and you are not forced to handle these.
aside from that, you'd just need to worry about OOMs and faults in native code.
“error” is simply bottom. Bottom is an inhabitant of every Haskell type. There’s no straightforward way to just turn it off.
That admittedly doesn't entail that Haskell ought to have special functions like 'error' that invite the programmer to explicitly introduce bottom values as a mechanism of signaling errors. However, in the real world, executing any function may raise an exceptional condition at any time (e.g. an out of memory error), regardless of programming language.
I don't understand: if the function you called doesn't terminate then you're blocked so I don't see why this should impact the types..
If it compiled before and worked and your refactored version also compiles, chances are you didn't break anything.
And I would say that if somebody never worked with Haskell (or some other language with a strong type system like Idris) they can bit fantom what is possible to encode in the type system.
It means you can run your unit tests without having to change everything everywhere all at once.
The flag is -fdefer-type-errors
all state is factored, so it can easily be refactored.
In my experience the ease of refactoring is more depending on the quality of the code you are refactoring than the language. That said, a strong type system helps avoiding stupid mistakes and Haskell have a very strong type system.
you can unplug, replug stuff at will