Sure, you can do this embedding, but the result will be extremely painful to program in|
I think you're overstating the case. First, with a macro system, there is zero overhead. Even without a macro system, it's not much of a burden; there is some boilerplate, but it only needs to be written once.
infixl 9 #
data O = Int Integer | Fun (O -> O)
(#) :: O -> O -> O
(Fun f) # x = f x
_ # _ = error "tried to apply non-function"
identity = Fun (\x -> x)
two = identity # Int 2
instance Eq O where ...
instance Ord O where ...
instance Enum O where ...
instance Num O where
(Int m) + (Int n) = Int (m+n)
_ + _ = error "tried to add non-integers"
seven = Int 3 + Int 4
What was so painful about that? The Fun which you need to prefix abstractions by is usually a keyword in ML-like languages, so it's certainly tolerable. And the fact that you have to write "#" for applications is arguably no worse than having to write parentheses around arguments in Algol-like languages.
And with a macro system, both these issues disappear, along with the need for the Int coercion. Furthermore, you can extend the language semantics in more-or-less arbitrary ways without having to fiddle with a compiler's source code. You could make the O type monadic, for example, and easily add state, continuations, and so on, or add new primitive datatypes, function memoization, OO features, whatever your heart desires, and I bet it will run faster than most simple DT implementations as well.
The notion that a ClassCastException could be thrown at runtime is apparently so abhorrent to the ocaml developers that they're willing to keep their object system weak in order to make this impossible.
Maybe that's the real problem. Once you've tasted of the forbidden fruit...
I'm not saying that there aren't problems with Ocaml's object system, or even that throwing an exception in this case is unreasonable, but I understand the reluctance to accept easy solutions if they don't fit the spirit of the language.
I like static languages but I can appreciate the DT advocates when they say that there will always be some interesting kinds of programs that ST languages won't be able to handle
There will always be some "interesting" kinds of programs that ST languages can't handle, true, but in practice 99% of what you code does not involve such programs, and when it does the ST analogue often has advantages over the unsafe version.
(without simulating a DT language, that is)
I think of it the other way around: DT languages are simulating ST languages. They do strictly less for the programmer, and ST programs carry more information. (A simulation of X is generally only an approximation of X; it carries less info.)