[MLton-user] Improved Exn.withEscape
Stephen Weeks
sweeks at sweeks.com
Mon Aug 28 14:58:07 PDT 2006
> A problem with the above design is that the type of withEscape should really
> be (with a well-known extension to the type system)
>
> ((Forall 'b. 'a -> 'b) -> 'a) -> 'a
Being able to return any type is one way to express that a function
doesn't return. One way to do this within the SML type system is to
use a "void" type that has no values. For example:
structure Void:>
sig
type t
end =
struct
type t = unit
end
val 'a withEscape: (('a -> Void.t) -> 'a) -> 'a =
fn f =>
let
exception E of 'a
in
f (fn x => raise E x) handle E x => x
end
It is certainly easier for the eye to pick out that the passed escape
function doesn't return when withEscape has the void type. Compare:
val withEscape: (('a -> Void.t) -> 'a) -> 'a
val withEscape: (('a -> 'b) -> 'a) -> 'a
With the void type, in order to use the escape function, it is
essential to have a way to convert the void type to any other type.
Here's a way.
val dead: 'a -> 'b = fn _ => raise Fail "dead"
With "dead" (the mnemonic is "dead code"), uses of withEscape look
like
withEscape (fn e => ... dead (e x) ... dead (e y) ...)
or, if there are a lot of uses one can name (and eta wrap) dead o e.
withEscape (fn e =>
let
val e = fn ? => (dead o e) ?
in
... e x ... e y ...
end)
There isn't a significant difference in client complexity between the
Exit.withLabel and the withEscape approaches. Compare the above to:
Exit.withLabel (fn l =>
let
val e = fn ? => Exit.exitTo l ?
in
... e x ... e y ...
end)
I think that the void withEscape expresses in the type system the
properties of what's going on more clearly than the Exit.withLabel
version. And, it doesn't require a specialized structure with a new
type and a couple of values to do it. One does need the Void
structure and dead function, but those are generally useful for
expressing the concept of a function not returning -- it seems better
to use that general concept in lots of places than to create a new
structure for each place.
So, my assessment is that the right way to go is the void withEscape.
More information about the MLton-user
mailing list