Meanwhile, I needed to implement coercions also since some unsafe terms couldn't be compiled by the more restrictive Hi-to-C compiler. (I've got three compilers, a compiler written in ML which translates Hi to ML called stage zero. A compiler written in Hi, with bindings to ML called stage one, which compiles to C. And, lastly, the same compiler but with dynamic bindings to C called stage two, only the system file differs. Essentially one and two are the same, I am making small patches to one to get it to accept two, almost itself.)
Anyway, coercions work in the following way
[ x: T -> f x | y: S -> g y | z -> z ]
A pattern may query a type (constructor), after which the variable is treated as having that type. Type coercions may occur anywhere in a pattern, if I implemented it correctly. The pattern instantiates a type which is used in the rewrite, but gives an unknown upward to be unified agains the other matches. The return of the block is the intersection of types of the rewrites, which pragmatically seems correct, but aesthetically, I wonder whether you'ld want to be able to unify unknowns there such that it becomes abstract in the return type also.
Its a straightforward feature I haven't seen in functional languages, so far. I needed it for handling exceptions since these are not type-checked, so to get at the value, the value needs to be coerced.
020510: Implemented and works. It needed some work on which types I query, once I need to factor that out too and build me a decent type handling library. Unmarshalling code depended on type-casts too, that mostly works now, there are some runtime/C bugs which shouldn't be hard to fix.