[MLton-user] Improved Exn.withEscape
Vesa Karvonen
vesa.karvonen at cs.helsinki.fi
Tue Aug 29 01:32:38 PDT 2006
Quoting Stephen Weeks <sweeks at sweeks.com>:
> 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.
[...]
> 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
val withLabel : ('a t -> 'a) -> 'a
(Just comparing to withLabel also.)
> 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"
Yes, I also considered the same basic approach. A combinator that I
often use when writing new code is undefined:
fun undefined _ = raise Fail "undefined"
> 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)
Well, I have withLabel and exitTo bound at the top-level for convenience
(although they are not used frequently). It is quite rare to need multiple
exitTo invocations in a single function so it usually doesn't make sense
to name it like above.
> 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.
I'm not so sure about that. It is well known that the H-M type system
infers polymorphic types for non-terminating terms. When I look at the
type of exitTo
val exitTo : 'a t -> 'a -> 'b
It is quite clear to me that it can't return normally.
The withLabel+exitTo approach also parallels the way callcc is often typed
in ML (http://mlton.org/MLtonCont).
> 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.
That's a better argument, but non-local returns as well as functions that
never return are somewhat of a special case. The structure where I have
withLabel and exitTo defined also contains other basic combinators so the
overhead you are describing is negligible (or non-existent).
I also worry about the efficiency of the implementation. The withLabel +
exitTo approach avoids having to build a closure and is likely to yield
slightly better generated code (on any compiler).
-Vesa Karvonen
More information about the MLton-user
mailing list