Not what you wish I’m afraid, but here’s how I believe you would go to implement it with affect (announced here).
IIUC, this happy eyeball algorithm just starts the tasks of a list every delay
seconds and returns the first one that succeeds (if any) and aborts the others it already started at that point.
Something like this would do I think. I didn’t test it though, it may be wrong :–)
let happy_eyeballs :
delay_s:float -> tries:(unit -> 'a option) list -> discard:('a -> unit) ->
'a option
=
fun ~delay_s ~tries ~discard ->
let either fst snd = match Option.join fst with
| None -> Option.join (Fiber.join snd)
| Some _ as v ->
Fiber.abort snd; Option.iter discard (Option.join (Fiber.join snd)); v
in
let rec loop = function
| [] -> None
| t :: ts ->
let t = Fiber.spawn t in
let ts = Fiber.spawn (fun () -> Funix.sleep_s delay_s; loop ts) in
match Fiber.first t ts with
| Either.Left t -> either t ts
| Either.Right ts -> either ts t
in
loop tries
Note that you can’t use Fiber.either
here, because it may drop a value without letting you discard it.