2017-07-22 6 views
1

Supposons que j'ai une fonction telle que:obtenir tout élément non-erreur dans une liste de report en OCaml/Async

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

Je produire une liste des requêtes différées:

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

Comment pour obtenir le résultat de la première requête qui n'échoue pas (ou une erreur sinon). Au fond, je voudrais une fonction telle que:

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

Aussi, je ne suis pas sûr de savoir comment agréger en quelque sorte les erreurs. Peut-être que ma fonction a besoin d'un paramètre supplémentaire tel que Error.t -> Error.t -> Error.t ou existe-t-il un moyen standard de combiner les erreurs?

Répondre

1

Une approche simple consisterait à utiliser Deferred.List qui contient les opérations de liste levées dans la monade Async, essentiellement une interface de conteneur dans la catégorie Kleisli. Nous allons essayer chaque serveur afin que le premier est prêt, par exemple,

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

Bien sûr, ce n'est pas any_non_error, que le traitement est séquentiel. En outre, nous perdons les informations d'erreur (bien que ce dernier est très facile à corriger). Donc, pour le rendre parallèle, nous emploierons la stratégie suivante. Nous aurons deux calculs différés, le premier exécutera toutes les requêtes en parallèle et attendra que tous soient prêts, le second sera déterminé dès qu'un résultat Ok sera reçu. Si le premier se produit avant le dernier, cela signifie que tous les serveurs ont échoué. Alors essayons:

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 
    ]