I am trying to use the Retry Monad I took from our beloved stack overflow:
type RetryBuilder(max, sleep : TimeSpan) =
member x.Return(a) = a
member x.Delay(f) = f
member x.Zero() = failwith "Zero"
member x.Run(f) =
let rec loop(n) =
if n = 0 then failwith "Failed"
else
try f()
with ex ->
sprintf "Call failed with %s. Retrying." ex.Message |> printfn "%s"
Thread.Sleep(sleep);
loop(n-1)
loop max
I would like to use it to make my file copy code a bit more robust:
let retry = RetryBuilder(3, TimeSpan.FromSeconds(1.))
retry {
System.IO.File.Move("a", "b")
}
Now I noticed that it sometimes fails with "Zero" exception. I tried to remove the member x.Zero() = failwith "Zero"
but now I get a compile time error:
This construct can be only used if builder defines a 'Zero' method.
Any ideas how to proceed?
It looks like the simplest fix is to return a value at the end:
retry {
System.IO.File.Move("a", "b")
return ()
}
If you look at how computation expressions are de-sugared your code seems to be converted into
retry.Run(retry.Delay(fun () -> System.IO.File.Move("a", "b"); retry.Zero()))
this causes the exception to be thrown during the evaluation. If you return a value this will not happen.