But the language will still be statically typed, as the correct resolution of a Dyn into an Integer, String etc, will still have to be ensured at compile time.
For example, I can define...
(+) :: Dyn -> Dyn -> Dyn
(+) (I x) (I y) = I (x + y) -- integer addition
(+) (S x) (S y) = S (x ++ y) -- string concat
So I can now use the + operator on variables of type Dyn. If a value has the wrong tag, then a pattern matching exception is thrown. Once I get enough primitive operations defined, I will never really have to manually unbox a value of Dyn type again.The one difficulty is emulating objects, because we would not have good syntax for arbitrary method calls. We could take a Smalltalk-like or Erlang-like approach, where the object takes message... the message being of type Dyn.
We should really look at dynamically typed languages as subsets of statically typed languages. In other words, they are not untyped, they are unityped. In other words, statically typed, but with exactly one type. This is the relationship between typed and untyped lambda calculus (untyped lambda calculus is actually typed, where every term has type Mu X. X -> X)
Of course, I'm just being pernickety, but that's how I am :)