A great type system is essential for all programming languages, but especially so for functional programming languages.

The issue however is that the problem of deciding which expressions are good and which ones aren't is undecidable.

Thus, languages only allow a subset of good expressions.
The goal is to make the type system as unrestrictive as possible while still retaining quick, static code analysis.
