StringCvt中的解析函数如果发现任何错误都可能引发异常,问题是引发的异常不包含任何精确的位置信息,因此其调用者无法知道究竟导致问题的原因。我首先想到的一个直接解决方案是引发包含问题流的异常,例如,更改
if W32.<(largestPosInt32, word)
then raise Overflow
else SOME(fromWord32 word, rest)
到
if W32.<(largestPosInt32, word)
then raise (Overflow rest)
else SOME(fromWord32 word, rest)
例外Overflow
将带有额外的rest
。但rest
属于多态类型,换句话说,假设函数类型为(char, 'a) StringCvt.reader -> (int, 'a) StringCvt.reader
,我想在此函数中引发异常exception ParseError of string * 'a
,但我不知道如何在标准ML中执行此操作。
还有其他解决问题的方法吗?提前谢谢。
再次更新。 我现在使用仿函数解决问题,但它不如简单的函数方便。骨架代码,
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
答案 0 :(得分:2)
声明带有抽象类型值的异常没有障碍,所以我不确定我理解你的问题。该异常将在抽象类型的签名中声明,并具有该类型的关联值。
答案 1 :(得分:2)
您可以在本地定义引用多态类型变量的异常,并且可以在本地引发和捕获它们。例如:
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
请注意,这不是多态异常 - 它相对于范围中的'a
类型是单态的,并且您只能将其应用于该类型的值,即仅x
因此,无法在全局范围内定义此类异常,因为全局范围内不存在任何类型变量(它们应绑定或实例化的位置?)。
您不能在SML中拥有真正的多态异常。原则上,通过存在量化可以实现这一点,但在实践中它不会非常有用。由于在匹配异常时无法知道类型,因此必须将类型视为完全抽象。例如:
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 *)
唯一有用的例子就是
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
但是没有理由不用不需要存在类型的简单版本来替换它:
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()
在实践中,没有人可能想要在异常中传递一流的ADT ......