如何在没有可变变量的情况下在F#中编写"重试"逻辑(只有1次迭代)?

ymp*_*tor 14 refactoring f#

因此,通过尝试避免可变变量,我提出了以下重试逻辑代码,这似乎很难看:

let result = TryConnect()
match result with
| ErrorConnecting ->
    SetupConnectionParameters()
    let resultAgain = TryConnect()
    match resultAgain with
    | ErrorConnecting ->
                      Console.Error.WriteLine("Setup failed!")
                      Environment.Exit(7)
    | Success(value) -> PerformOperations(value)
| Success(value) -> PerformOperations(value)
Run Code Online (Sandbox Code Playgroud)

有没有办法减少一些重复?(记住,没有mutablevars.)谢谢!

The*_*ght 12

由于此处显示了许多替代方案,因此这是另一个:

let private tryConnectNth n = 
    if n <> 0 then SetupConnectionParameters()
    TryConnect()

let isSuccess = function
    |Success _ -> true
    |ErrorConnecting -> false

let tryConnect n =
    Seq.init n tryConnectNth // generate a sequence of n connection attempts
    |> Seq.tryFind isSuccess // try to find the first success - returns Option
    |> Option.fold (fun _ -> id) ErrorConnecting // return ErrorConnecting if None, or result otherwise
Run Code Online (Sandbox Code Playgroud)

SetupConnectionParameters()仅在非零连接尝试时调用,并且最多重复n次.


Van*_*oiy 8

使用重试参数使函数递归:

let rec private tryToConnectAux tryAgain =
    match TryConnect() with
    | Success(value) -> PerformOperations(value)
    | ErrorConnecting when tryAgain ->
        SetupConnectionParameters ()
        tryToConnectAux false
    | ErrorConnecting ->
        Console.Error.WriteLine("Setup failed!")
        Environment.Exit(7)
Run Code Online (Sandbox Code Playgroud)

通过电话tryToConnectAux true.


这个答案被编辑了.原始代码:

let rec tryConnecting nRetries =
    match TryConnect() with
    | ErrorConnecting ->
        if nRetries > 0 then tryConnecting (nRetries - 1)
        else
            Console.Error.WriteLine("Setup failed!")
            Environment.Exit(7)
    | Success(value) -> PerformOperations(value)
Run Code Online (Sandbox Code Playgroud)

(此版本不包括SetupConnectionParameters(),您必须在适当的任何位置添加它)


The*_*Fox 8

您可以将重试逻辑分离为单独的函数.这是一个有很多打印到控制台的例子来说明正在发生的事情.

let rec retry f tries =
    printfn "Trying..."
    match f () with
    | Some successValue ->
        printfn "Success"
        Some successValue
    | None ->
        match tries with
        | [] ->
            printfn "Failed"
            None
        | delayMs :: rest ->
            printfn "Waiting %i ms..." delayMs
            System.Threading.Thread.Sleep(delayMs:int)
            retry f rest

let random = System.Random()

let connect () =
    if random.Next(100) < 30 then Some "connection"
    else None

match retry connect [100; 100] with
| Some connection -> printfn "Do something with connection."
| None -> printfn "Could not connect."
Run Code Online (Sandbox Code Playgroud)

尝试运行几次最后一个表达式.

  • 这为您提供了灵活的尝试次数,每次尝试都有可选的延迟(提供的延迟次数是重试次数).

  • 应该可以调整您的代码以使用该retry功能.您需要创建一个尝试连接一次的函数,Some如果成功,则返回包装的连接,或者只是None失败.然后将该函数作为f参数传递.