假设在您进入长时间运行的流程之前,您必须执行一些预启动检查。
假设一旦满足这些检查,您就不需要再次进行检查(可能有很多检查并且执行起来也相对昂贵)。
如何在这里避免国家?
更一般地说,在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 ()
答案 0 :(得分:6)
我看到你的conditionChecks
函数在每个false
值之后递归。在我看来,你正在尝试编写以下算法:
在我看来,每个条件检查都是某种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"
当然,为我运行会产生不同的结果,但它们通常看起来像这样:
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
正如您所看到的,条件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 ()
}
您可能不需要这个额外的功能,但它可能会派上用场。
此外,如果您无法并行运行条件但它们必须按顺序运行,则将let ready = ...
行替换为:
let ready = allConditions |> List.map Async.RunSynchronously
当然,最后使用List.reduce
代替Array.reduce
。
答案 1 :(得分:2)
我认为懒惰的价值在这里会很好用。
你可以让懒惰值存储一个函数的结果,然后它为你做缓存。