Is it possible to raise exceptions with precise stream location information in StringCvt.scanInt functions?

StackOverflow https://stackoverflow.com/questions/20451058

質問

Parsing functions in StringCvt may raise exceptions if they find anything wrong, the problem is the raised exception doesn't contain any precise location information, so its caller can not know where exactly causes the problem. One direct solution in my first thought is to raise an exception containing the problem stream, for example, changing

if W32.<(largestPosInt32, word)
then raise Overflow
else SOME(fromWord32 word, rest)

to

if W32.<(largestPosInt32, word)
then raise (Overflow rest)
else SOME(fromWord32 word, rest)

The exception Overflow will carry the additional rest. But rest is of an polymorphic type, in other words, suppose the function is of type (char, 'a) StringCvt.reader -> (int, 'a) StringCvt.reader, I want to raise an exception exception ParseError of string * 'a in this function, but I don't know how to do this in Standard ML. Any other solutions to the problem please? Thanks in advance.

Update again. I use a functor to work around the problem now, but it is not as convenient as a simple function. The skeleton code,

functor Foo(structure arg : sig
                            type opaque
                            type stream
                            val refopaque : stream -> opaque
                            end) :
sig
type opaque
type stream
exception SomeError of string * opaque
end =
struct
type opaque = arg.opaque
type stream = arg.stream
val refopaque = arg.refopaque
exception SomeError of string * opaque
fun parse getc cs
... raise SomeError("error", refopaque cs)
...
end
役に立ちましたか?

解決

You can locally define exceptions that refer to polymorphic type variables, and you can raise and catch them locally. For example:

fun 'a f(x : 'a) =
    let
      exception E of 'a
      fun g() = raise E x
      fun h() = g() handle E y => y
    in
      h()
    end

Note that this is not a polymorphic exception, though -- it is monomorphic relative to the type 'a in scope, and you can only apply it to values of that type, i.e., only x.

Consequently, there is no way to define such an exception globally, because no type variables can exist in the global scope (where should they be bound or instantiated?).

You cannot have truly polymorphic exceptions in SML. In principle, allowing this would be possible via existential quantification, but it would not be very useful in practice. Since there would be no way of knowing the type when matching an exception, the type would have to be treated as fully abstract. For example:

exception E of 'a  (* hypothetical existential exception *)
fun f1() = raise E 1
fun f2() = raise E "foo"
fun g f = f() handle E x => ()  (* type of x is abstract here *)

The only marginally useful example would be something like

exception E of ('a -> int) * 'a
fun f1() = raise E(fn x => x, 1)
fun f2() = raise E(String.size, "foo")
fun g f = f() handle E(h, x) => h x

But there is little reason not to replace this with a simpler version that does not require existential types:

exception E of unit -> int
fun f1() = raise E(fn() => 1)
fun f2() = raise E(fn() => String.size "foo")
fun g f = f() handle E h => h()

In practice, nobody probably wants to pass around a first-class ADT in an exception...

他のヒント

There is no obstacle to declaring exceptions that carry values of an abstract type, so I am not sure I understand your question. The exception would be declared in the signature of the abstract type with an associated value of that type.

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top