I just don't know that, is there any technical reason for that? Is it more difficult to implement a compiler for a language with weak typing? What is it?
The premises behind the question are a bit dodgy. It is not true that interpreted languages are mostly ducktyped. It is not true that compiled languages mostly have strong typing. The type system is a property of a language. Compiled versus interpreted is a property of an implementation.
Examples:
The programming language Scheme is dynamically typed (aka duck-typed), and it has many dozens of interpreted implementations, but also some fine native-code compilers including Larceny, Gambit, and PLT Scheme (which includes both an interpreter and a JIT compiler making seamless transitions).
The programming language Haskell is statically typed; the two most famous implementations are the interpreter HUGS and the compiler GHC. There are several other honorable implementations split about evenly between compiling to native code (yhc) and interpretation (Helium).
The programming language Standard ML is statically typed, and it has had many native-code compilers, of which one of the best and most actively maintained is MLton, but one of the most useful implementations is the interpreter Moscow ML
The programming language Objective Caml is statically typed. It comes with only one implementation (from INRIA in France) but this implementation includes both an interpreter and a native-code compiler.
The programming language Pascal is statically typed, but it became popular in the 1970s because of the excellent implementation built at UCSD, which was based on a P-code interpreter. In later years fine native-code compilers became available, such as the IBM Pascal/VS compiler for the 370 series of computers.
The programming language C is statically typed, and today almost all implementations are compiled, but in the 1980s those of us lucky enough to be using Saber C were using an interpreter.
Nevertheless there is some truth behind your question, so you deserve a more thoughtful answer. The truth is that dynamically typed languages do seem to be correlated with interpreted implementations. Why might that be?
Many new languages are defined by an implementation. It is easier to build an interpreter than to build a compiler. It is easier to check types dynamically than to check them statically. And if you are writing an interpreter, there is little performance benefit to static type-checking.
Unless you are creating or adapting a very flexible polymorphic type system, a static type system is likely to get in the programmer's way. But if you are writing an interpreter, one reason may be to create a small, lightweight implementation that stays out of the programmer's way.
In some interpreted languages, many fundamental operations are so expensive that the additional overhead of checking types at run time doesn't matter. A good example is PostScript: if you're going to run off and rasterize Bezier curves at the drop of a hat, you won't balk at checking a type tag here or there.
Incidentally, please be wary of the terms "strong" and "weak" typing, because they don't have a universally agreed technical meaning. By contrast, static typing means that programs are checked before being executed, and a program might be rejected before it starts. Dynamic typing means that the types of values are checked during execution, and a poorly typed operation might cause the program to halt or otherwise signal an error at run time. A primary reason for static typing is to rule out programs that might have such "dynamic type errors". (This is another reason people who write interpreters are often less interested in static typing; execution happens immediately after type checking, so the distinction and the nature of the guarantee aren't as obvious.)
Strong typing generally means that there are no loopholes in the type system, whereas weak typing means the type system can be subverted (invalidating any guarantees). The terms are often used incorrectly to mean static and dynamic typing. To see the difference, think of C: the language is type-checked at compile time (static typing), but there are plenty of loopholes; you can pretty much cast a value of any type to another type of the same size---in particular, you can cast pointer types freely. Pascal was a language that was intended to be strongly typed but famously had an unforeseen loophole: a variant record with no tag.
Implementations of strongly typed languages often acquire loopholes over time, usually so that part of the run-time system can be implemented in the high-level language. For example, Objective Caml has a function called Obj.magic
which has the run-time effect of simply returning its argument, but at compile time it converts a value of any type to one of any other type. My favorite example is Modula-3, whose designers called their type-casting construct LOOPHOLE
.
In summary:
Static vs dynamic is the language.
Compiled vs interpreted is the implementation.
In principle the two choices can be and are made orthogonally, but for sound technical reasons dynamic typing frequently correlates with interpretation.