I believe that dynamic typing results from frustration over generics, rather than over static typing in general. (Type stuttering is another problem, but modern languages solve it with local type inference.) I mean, annotating non-generic functions is always straightforward doesn't introduce much complexity:
# s should be str
# returns nothing
def print(s):
...
# just becomes (using Py3 annotation syntax)
def print(s: str) -> None:
...
However, it's much harder to write a type annotation of generic functions. Worse, remember that Python's map is variadic. # for any types t0, t1, t2, ... tn:
# fn is a function that takes arguments of types t0, t1, ... t(n-1)
# and returns a value of type tn;
# seqs are iterables of types t0, t1, ... t(n-1);
# returns a list of type tn.
def map(fn, *seqs):
...
# How to write this signature is non-obvious
Many mature static typing systems would allow you to express such types (usually called parameterized types). But any one of them would require more than those trivial notations in print.That's when the dynamic typing people get annoyed and go "fxxk static typing systems, I can handle this in my mind". Which is about 65% (totally random estimation) the point of dynamic typing in my opinion.
Any type checker for dynamic typed languages that doesn't seriously try to solve the generics problem is not genuinely interesting.