Types are the cheapest semantic documentation you can write, and your compiler/type checker can provide additional guarantees based on them.
Not only that, they're notes to future contributors/yourself about how a program works, so they/you don't have to reverse engineer code that was written a while ago in order to modify it with confidence.
> Types are the cheapest semantic documentation you can write
They are not.
Unfortunately, especially Haskell world seems to think they replace documentation, that's why so much of "documentation" for a lot of Haskell libs are just a dump of types with no explanation of what they mean, how they interact, what the functions using them do, or how they can be used.
> they're notes to future contributors/yourself about how a program works
They are not. Types do not describe how a program works.
> so they/you don't have to reverse engineer code that was written a while ago in order to modify it with confidence.
Yes, you will have to reverse engineer code that was written a while ago. Because types only describe, well, types. You code contains logic. And logic is the hardest part to understand.
Personal anecdote: worked on a system that was transitioning from original ad-hoc implementation to a better designed one. Some functions would accept a Person. Others would accept a Contact. Why? How to convert between the two? What are the differences? What was behind the decision? Why did `is_empty(new_contact())` returned `false`? And so on.
Thank god it had types, right? No need to reverse engineer.
Types are the cheapest semantic documentation you can write, and your compiler/type checker can provide additional guarantees based on them.
Not only that, they're notes to future contributors/yourself about how a program works, so they/you don't have to reverse engineer code that was written a while ago in order to modify it with confidence.