我正在尝试使用从我们心爱的堆栈溢出中获取的重试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我想使用它使我的文件副本代码更健壮一些:
let retry = RetryBuilder(3, TimeSpan.FromSeconds(1.))
retry {
    System.IO.File.Move("a", "b")
}现在,我注意到,有时在出现"Zero“异常时会失败。我试图删除member x.Zero() = failwith "Zero",但现在我得到了一个编译时错误:
只有当构建器定义了“Zero”方法时,才能使用此构造。
有什么办法吗?
发布于 2014-04-17 10:49:38
看起来最简单的解决方法是在最后返回一个值:
retry {
    System.IO.File.Move("a", "b")
    return ()
}如果您查看计算表达式是如何计算的?,您的代码似乎被转换为
retry.Run(retry.Delay(fun () -> System.IO.File.Move("a", "b"); retry.Zero()))这将导致计算期间抛出异常。如果您返回一个值,则不会发生这种情况。
发布于 2014-04-17 12:02:10
Lee建议您可以在计算结束时使用return (),否则会抛出,因为它们调用Zero成员。这是一个很好的技巧,但实际上您可以将其直接集成到计算生成器中。
当计算结束而不返回时,将使用Zero成员。您可以更改它以执行与return ()相同的操作。
type RetryBuilder(max, sleep : TimeSpan) = 
  member x.Return(a) = ...
  member x.Zero() = x.Return( () )然后只需编写原始代码,就可以得到单元结果:
let retry = RetryBuilder(3, TimeSpan.FromSeconds(1.))
retry {
  System.IO.File.Move("a", "b")
}发布于 2014-04-17 11:12:09
首先,需要对x.Run函数进行类型注释,以使编译器高兴,因为File.Move接受单元并返回单元。就像这样:
open System
open System.Threading
type RetryBuilder(max, sleep : TimeSpan) = 
      member x.Return(a) = a
      member x.Delay(f) = f
      member x.Zero() = failwith "Zero"
      member x.Run(f : unit -> unit) =
        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然后查看Zero()函数上的文档,我们看到“在计算表达式中调用if...then表达式的空of分支”。因此,这就解释了为什么编译器需要在计算表达式中显示Zero。然后,如果我们在' if‘上设置一个断点,然后看着它执行,我们就会看到文件移动返回单元,这样其他人就没有什么可返回的了,因此它调用Zero。因此,这解释了为什么在移动成功时会弹出Zero (然后当它失败时重试,因为文件已经被移动并且不再存在)。
https://stackoverflow.com/questions/23129731
复制相似问题