OCaml中的多态异常参数



在OCaml中,可以定义自己的异常,这些异常可以接受参数,如下面的代码段所示。

exception there_is_a_problem of string

我想知道是否有一种方法可以在它们的参数中使用多态的异常。一个示例应用程序是遍历数据结构的快捷方式。例如,我希望能够按照以下几行写一些东西。

exception Found_it of 'a
let find_opt test l =
let aux elt = if test elt then raise (Found_it elt) in
try List.iter aux l; None with
| Foundit b -> Some b

我实际的数据结构比列表更复杂,我更喜欢使用迭代器来遍历它,所以我不能像stdlibList.find_opt那样编写find_opt。我目前的解决方案是使用如下参考。我觉得上面的风格更优雅,但我现在大多只是感到好奇。我的另一个解决方案是定义一个新的通用折叠迭代器,如果满足某些输入测试,它可以缩短计算,但这需要访问数据结构的实现。

let find_opt' test l =
let store = ref None in
let aux elt = if test elt then (store := Some elt; raise Exit) in
(try List.iter aux l with Exit -> ());
!store

这段代码似乎非常接近您的要求:

let f (type a) test (l: a list) =
let module M = struct exception F of a end in
let aux elt = if test elt then raise (M.F elt) in
try List.iter aux l; None
with M.F b -> Some b

也许有一个更简单的方法,但这就是我想到的。

更新

此代码使用本地抽象类型,OCaml手册第10.4章对此进行了描述。

在阅读刚才的手册时,我注意到它建议使用本地抽象类型来满足您的需求!这让我更有信心我的答案很好:-(

另一个选项是使用with_return函数(例如Base有一个(:

let find_opt' test l =
with_return ( fun {return} ->
List.iter (fun elt -> if test elt then return (Some elt)) l; None
)

诀窍是让with_return函数定义一个新的异常(带有本地抽象(,并提供一个多态函数,向用户引发新的异常:

type 'a return = { return: 'never. 'a -> 'never }
let with_return (type a) f =
let exception Return of a in
let return x = raise (Return x) in
try f {return} with Return x -> x

类型return可能看起来很奇怪,但它表达了一个事实,即内部return函数永远不会返回到当前上下文,并且总是引发异常。如此精确使得在更多的上下文中使用return函数成为可能。例如,在下面的示例中,

let l = with_return (fun {return} ->
let integer = if test () then return () else 1 in
let list = if test () then return () else [1] in
integer :: list
)

return首先用于期望返回int的上下文中,然后用于期望int list的上下文中。如果没有显式多态注释,这将是一个类型错误。

最新更新