重试monad和Zero构造

Kla*_*ark 3 monads f# computation-expression

我正在尝试使用我从心爱的堆栈溢出中获取的Retry Monad:

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
Run Code Online (Sandbox Code Playgroud)

我想用它来使我的文件复制代码更健壮:

let retry = RetryBuilder(3, TimeSpan.FromSeconds(1.))
retry {
    System.IO.File.Move("a", "b")
}
Run Code Online (Sandbox Code Playgroud)

现在我注意到它有时会因"零"异常而失败.我试图删除member x.Zero() = failwith "Zero"但现在我得到一个编译时错误:

仅当构建器定义"零"方法时,才能使用此构造.

任何想法如何进行?

Tom*_*cek 9

Lee建议你可以return ()在计算结束时使用,否则会抛出,因为他们称之为Zero成员.这是一个很好的技巧 - 但您实际上可以将其直接集成到计算构建器中.

Zero当您的计算结束而不返回时,将使用该成员.你可以改变它来做同样的事情return ():

type RetryBuilder(max, sleep : TimeSpan) = 
  member x.Return(a) = ...
  member x.Zero() = x.Return( () )
Run Code Online (Sandbox Code Playgroud)

然后你可以编写原始代码,然后你会得到单位结果:

let retry = RetryBuilder(3, TimeSpan.FromSeconds(1.))
retry {
  System.IO.File.Move("a", "b")
}
Run Code Online (Sandbox Code Playgroud)