Compilers + Static types = efficient machine code
Compilers + Dynamic types = inefficient machine code
Consider the following pseudocode:
function foo(a, b) {
return a+b
}
A Static language will be able to know (by declaration or inference) that a and b are integers, and will compile down to
%reg = addi a,b
or something similar, anyway.
A compiler for a dynamic language would have to emit code to
1. Check they types of a and b
2. handle each case or combination of cases
%reg1 = typeof a
beq %reg1, int, a_int_case
beq %reg1, float, a_float_case
beq %reg1, string, a_string_case
label a_int_case
%reg1 = typeof b
beq %reg1, int, a_int_b_int_case
beq %reg1, float, a_int_b_float_case
beq %reg1, string, a_int_b_string_case
label a_int_b_int_case
%out = addi a,b
goto done
label a_int_b_float_case
%tmp = mkfloat a
%out = addf %tmp,b
goto done
... Etc. I can't finish
While you could generate smarter machine code than that, you wouldn't be able to help generating lots of code -- That makes compilation not a major win for a dynamic language.
Since interpreters are much easier to write, and compilation doesn't do you much good, why not write an interpreter?
(Just-in-time compilers actually have type information, and can compile right down to the single statement. They actually have more information than static type systems, and can theoretically do even better. All assembler is simulated; Any resemblance to real code that could run on a real machine is purely coincidental.)