
True enough, in a sense, a dynamically typed language is like a statically typed language with only one type (probably several by distinguishing function types) and many incomplete pattern matches. So, you can embed a dynamically typed language into a strongly typed language without loosing static type checking.
statically typed: typed at compile time dynamically typed: typed at runtime weakly typed: .. strongly typed: everything is typed and type-checked there are at least two problems with embedding strongly and dynamically typed languages into strongly and statically typed languages: - it assumes that there is a globally unique static stage, entirely separate from a globally unique dynamic stage - it assumes that there is a unique, unchanging (closed) world of types static typing alone is too static to deal with dynamically evolving types or flexible ideas such as runtime compilation or dynamic linking.. the solution is long-known as type Dynamic (a universal type in which expressions are paired with type tags): projecting from a Dynamic to the tag type (using a typecase) involves a 'static' type check prior to stripping the type info away for a limited 'runtime', embedding into a Dynamic involves creating a runtime type tag, to prepare for situations that can't be handled statically. if you have a strongly and otherwise statically typed language extended with Dynamic/typecase, you can embed strongly and dynamically typed languages into it. and you can try to reduce the number of Dynamic and typecase uses to a minimum, giving you maximal phases of pre-checked runtime without dynamic type representations or type checks. but there are situations that need Dynamic/typecase. if you have a strongly and dynamically typed language, you can embed strongly and statically typed languages into it. by default, that means you get more type-checks than necessary and type-errors later than you'd wish, but you still get them. eliminating runtime type information and runtime type-checks in a strongly and dynamically typed language is a question of optimisation, similar to deforestation. if you have a strongly and statically typed language, there are situations where you'll get stuck. extending the type system may get you beyond some of these barriers, but only to the next set of problems. it is impressive just how far languages like haskell have managed to take the idea of strong static typing, and it is worthwhile noting that many people need nothing more most of the time. it is also worthwhile recalling that the struggle involved has given us type systems that can handle many of the problems that were thought to be dynamic in nature within a static type system (such as generic programming). but there always remains a small set of essential problems that exceed what strong static typing can handle on its own. adding Dynamic/typecase gives you the best of both worlds: the expressiveness of strongly and dynamically typed languages and the efficiency and early safety (between a typecase and a reembedding into Dynamic, there will be no runtime type-checks and no runtime type-errors) of strongly and statically typed languages. even better, for the large number of programs that do not need dynamic types, there'll be no sign of them - those programs work in the strongly and statically typed subset of the language. claus