从OCaml / Async中的延迟列表中获取任何非错误元素

时间:2017-07-22 10:55:14

标签: asynchronous error-handling ocaml

假设我有一个如下功能:

query_server : Server.t -> string Or_error.t Deferred.t

然后我生成一个延迟查询列表:

let queries : string Or_error.t Deferred.t list = List.map servers ~f:query_server

如何获得第一个没有失败的查询的结果(否则会出现一些错误)。基本上,我喜欢这样的功能:

any_non_error :  'a Or_error.t Deferred.t list -> 'a Or_error.t

另外,我不确定如何以某种方式汇总错误。也许我的函数需要一个额外的参数,比如Error.t -> Error.t -> Error.t,或者是否有一种标准的方法来组合错误?

1 个答案:

答案 0 :(得分:1)

一种简单的方法是使用Deferred.List包含提升到Async monad中的列表操作,基本上是Kleisli类别中的容器接口。我们将按顺序尝试每台服务器,直到第一台服务器准备就绪,例如

let first_non_error = 
  Deferred.List.find ~f:(fun s -> query_server s >>| Result.is_ok)

当然,它不是any_non_error,因为处理是连续的。此外,我们正在丢失错误信息(尽管后者很容易修复)。

因此,为了使其平行,我们将采用以下策略。我们将有两个延迟计算,第一个将并行运行所有查询并等待所有准备就绪,第二个将在收到Ok结果后立即确定。如果第一个发生在最后一个之前,那么这意味着所有服务器都失败了。所以让我们试试:

 let query_servers servers = 
   let a_success,got_success = Pipe.create () in
   let all_errors = Deferred.List.map ~how:`Parallel servers ~f:(fun s -> 
      query_server s >>| function
      | Error err as e -> e
      | Ok x as ok -> Pipe.write_without_pushback x; ok) in
   Deferred.any [
       Deferred.any all_errors;
       Pipe.read a_success >>= function
       | `Ok x -> Ok x
       | `Eof -> assert false
   ]