Python has optional typing with mypy and its annotations though, but I'd go for tests first not types and maybe generate the types from the tests : ). Tests can't check every code path like types, but they catch more errors overall and they are a better form of documentation.
which is easier to understand:
filter(pred: Function[A]->Boolean, seq: Sequence[A]) -> Sequence[A]
% isOdd = lambda: x % 2 == 0
% list(filter(isOdd, range(0, 6)))
[1, 3, 5]
The unit test which is the same as replacing the types with actual values, can tell you more about the function because it actually tells you what the function actually does, and the types just tell you that you take in a Sequence and return a Sequence while the example test tells you that the return value is a subset of the sequence and that it uses the pred function to create that subset. You can generate the types from the test values BTW, and its easier for someone to generalize values to types than the opposite. Also types give you a false sense of security, and they can't check that you wrote your filter function correctly because all they care about is the domain of the values not what the function ACTUALLY does.
You're making the comparison by using the most useless example of types imaginable. For a fair comparison you'd be using at least Elm's type system, but preferably Haskell's or even Agda's.
We're a place where coders share, stay up-to-date and grow their careers.
We strive for transparency and don't collect excess data.