我有一段 F# 代码,可以找到能够被1到20之间所有数字整除的最小正整数。该代码执行时间为10秒。
let isDivisableByAll num (divisors: int[]) = Array.forall (fun div -> num % div = 0) divisors
let minNumDividedBy (divisors: int[]) =
let rec minNumDividedByAll stopAt acc =
if acc >= stopAt then 0
else if isDivisableByAll acc divisors then acc
else minNumDividedByAll stopAt (acc + 1)
minNumDividedByAll 400000000 1
minNumDividedBy [|1..20|]
所以,我认为可以让它更加优雅一些,因为我更喜欢简洁的代码,于是写下了以下内容。
let answer = { 1..400000000 }
|> Seq.tryFind (fun el -> isDivisableByAll el [|1..20|])
这花了10分钟!我无法解释其中的巨大差异,因为序列是懒惰的。为了调查,我写了一个命令式循环。
let mutable i = 1
while i < 232792561 do
if isDivisableByAll i [|1..20|] then
printfn "%d" i
i <- i + 1
用了8分钟,因此,也不是序列的问题,对吧?那么,为什么初始函数会如此快呢?它不可能通过尾递归避免建立堆栈,是吗?因为我也不指望在慢的示例中建立任何可观的堆栈。
这对我来说没有太多意义,有人能告诉我原因吗?
谢谢。
[|1..20|]
移到循环外面,我认为速度会更快。 - John Palmer