避免表示状态的可变布尔值

pro*_*rth 3 f#

假设在进入长时间运行的进程之前,必须执行一些预启动检查.

还假设一旦满足这些检查,您就不需要再次进行检查(可能有许多检查并且执行起来也相对昂贵).

如何在这里避免国家?

更一般地说,在Python中,你可以使用类似于生成器或协同程序的东西来保存这些检查和状态.是否有一个很好的F-sharpy方法摆脱可变的布尔值,以表明跳过每个满意的检查?

let r = new System.Random()

let someCondition1 () = 
    r.Next() % 523452321 = 0 

let someCondition2 () = 
    r.Next() % 243142321 = 0 

let mutable conditionCheck1 = false
let mutable conditionCheck2 = false
let rec conditionChecks () =

    match conditionCheck1 with
    | true -> ()
    | false -> match someCondition1 () with
               | false -> conditionChecks ()
               | true  -> conditionCheck1 <- true // never check again

    match conditionCheck2 with
    | true -> ()
    | false -> match someCondition2 () with
               | false -> conditionChecks ()
               | true  -> conditionCheck2 <- true // never check again

let rec eventLoop () =
    eventLoop ()

conditionChecks ()
eventLoop ()
Run Code Online (Sandbox Code Playgroud)

rmu*_*unn 6

我看到你的conditionChecks函数在每个false值之后都会递归.在我看来,你正在尝试编写以下算法:

  1. 为每个要检查的条件编写一个函数.
  2. 等待所有条件成为现实.(继续重新检查任何错误的情况).
  3. 继续事件循环.

在我看来,每个条件检查都是某种async表达式,这将是一个很好的解决方案.该async会继续运行,直到条件为真,然后完成并返回一个true值.然后,您将在列表中收集异步,并同步运行整个asyncs列表.奖励:如果条件是他们的支票可以并行执行,这将节省您的时间.

let r = new System.Random()

let rec someCondition1 () =
    async {
        // if r.Next() % 523452321 = 0 then
        printfn "Checking condition 1"
        if r.Next() % 52 = 0 then  // So our output is shorter
            return true
        else
            return! someCondition1 ()
    }

let rec someCondition2 () = 
    async {
        // if r.Next() % 243142321 = 0 then
        printfn "Checking condition 2"
        if r.Next() % 24 = 0 then  // So our output is shorter
            return true
        else
            return! someCondition2 ()
    }

let allConditions = [
    someCondition1 ()
    someCondition2 ()
]

let rec eventLoop () =
    printfn "Event loop runs now"
    // eventLoop ()  // Disabled so our test run will not infiloop

let ready = allConditions |> Async.Parallel |> Async.RunSynchronously
if Array.reduce (&&) ready then
    eventLoop()
else
    printfn "Some conditions returned false somehow"
Run Code Online (Sandbox Code Playgroud)

当然,为我运行这个产生了不同的结果,但它们通常看起来像这样:

Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 2
Checking condition 2
Checking condition 1
Checking condition 2
Checking condition 1
Checking condition 2
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Checking condition 1
Event loop runs now
Run Code Online (Sandbox Code Playgroud)

正如你所看到的,条件2设法true在第四次尝试时返回并停止 - 而条件1在获得true结果之前需要大约二十五次尝试.但是一旦得到所有结果true,事件循环就会运行.

顺便说一句,我写这个的方式也允许在条件检查中"中止".如果任何条件检查可以确定它永远不会令人满意,它可能会返回false,在这种情况下,事件循环将不会运行.所以:

let condition1CanNeverBeTrue () =
    r.Next() % 123456789 = 0

let rec someCondition1 () =
    async {
        if r.Next() % 523452321 = 0 then
            return true
        else
            if condition1CanNeverBeTrue() then
                return false
            else
                return! someCondition1 ()
    }
Run Code Online (Sandbox Code Playgroud)

您可能不需要这个额外的功能,但它可能会派上用场.

此外,如果您不能并行运行条件但它们必须按顺序运行,则将let ready = ...行替换为:

let ready = allConditions |> List.map Async.RunSynchronously
Run Code Online (Sandbox Code Playgroud)

而且,当然,List.reduce而不是Array.reduce在最后使用.