Dynamic typing would be less of an issue if it wasn't a pain to verify what you're actually working with.
In Python, adding
assert isinstance(x, Y), x
everywhere is a lot of effort, let alone a full
if not isinstance(x, Y): raise Exception('blahblab')
However, with pattern matching you can check more easily you're working with the right data (barring someone intentionally trying to fuck up, which no language protects against).
For example, Erlang, which is still on my to-learn list:
Code:
Stuff = {list_of_stuff, [a,b,c]}.
% Ok
{list_of_stuff, List} = Stuff.
% Kaboom
{something_else, Idk} = Stuff.
Here only identifiers starting with an uppercase letter are variables. Lowercase identifiers are atoms, which in patterns only match against identical atoms.
If you haven't, take a stab at a functional programming language, pattern matching is great.