OCaml中的多态异常参数

问题描述 投票:0回答:2

在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

我的实际数据结构比列表更复杂,我更喜欢使用迭代器遍历它,因此我无法像stdlib find_opt一样编写List.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
exception polymorphism ocaml traversal
2个回答
2
投票

此代码似乎与您要的内容非常接近:

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

可能有一种更简单的方法,但这是我想出的。

更新

此代码使用本地抽象类型,在Section 8.5 of the OCaml manual中有描述。

虽然现在正在阅读手册,但我发现它建议针对您所要求的情况使用局部抽象类型!这使我更有信心,我的回答非常好:-)


0
投票

另一种选择是使用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的上下文中使用。如果没有显式多态注释,这将是类型错误。

© www.soinside.com 2019 - 2024. All rights reserved.