A good type system does not prevent you from making logic errors. It's just another level of protection, like managed memory. In the same way that reference counting prevents you from leaking memory, a type system prevents certain kinds of mistakes that are generally solved with discipline in other programming languages - for example, in Python, I can construct the following program:
def greater_than(a, b):
return a > b
if __name__ == '__main__':
print(greater_than(5, 4))
print(greater_than([], 4))
Which is a perfectly valid program, but throws a runtime error. However, in Haskell:
module Main where
greater_than :: (Ord a) => a -> a -> Bool
greater_than a b = a > b
main = do
print $ greater_than 5 4
print $ greater_than [] 4
I have added a constraint that forces the caller to pass a value that can be compared - and the compiler will throw an error if I don't do that.
Of course this won't get rid of every problem programmers face, but it helps.
Of course this won't get rid of every problem programmers face, but it helps.