I’m curious as to how often experienced Haskell programmers really use type inference in practice. I often see it praised as an advantage over the always-explicit declarations needed in certain other languages, but for some reason (perhaps just because I’m new) it ‘feels’ right to write a type signature just about all the time… and I’m sure in some cases it really is required.
Can some experienced Haskellers (Haskellites? Haskellizers?) provide some input?
It’s still an advantage, even if you write type signatures, because the compiler will catch type errors in your functions. I usually write type signatures too, but omit them in places like
whereorletclauses where you actually define new symbols but don’t feel the need to specify a type signature.Stupid example with a strange way to calculate squares of numbers:
oddsandsumsare functions that would need a type signature if the compiler wouldn’t infer them automatically.Also if you use generic functions, like you usually do, type inference is what ensures that you really combine all those generic functions together in a valid way. If you, in the above example, say
The compiler can deduce that this isn’t valid this way, because one of the used functions (the
oddfunction from the standard library), needsato be in the type classIntegral. In other languages you usually only recognize this at a later point.If you write this as a template in C++, you get a compiler error when you use the function on a non-Integral type, but not when you define the template. This can be quite confusing, because it’s not immediately clear where you’ve gone wrong and you might have to look through a long chain of error messages to find the real source of the problem. And in something like python you get the error at runtime at some unexpected point, because something didn’t have the expected member functions. And in even more loosely typed languages you might not get any error, but just unexpected results.
In Haskell the compiler can ensure that the function can be called with all the types specified in it’s signature, even if it’s a generic function that is valid for all types that fulfill some constrains (aka type classes). This makes it easy to program in a generic way and use generic libraries, something much harder to get right in other languages. Even if you specify a generic type signature, there is still a lot of type inference going on in the compiler to find out what specific type is used in each call and if this type fulfills all the requirements of the function.