Таким образом, в целом, при использовании функциональных идиом, вы, вероятно, ожидаете, что будете немного медленнее, чем при использовании императивной модели, потому что вам нужно создавать новые объекты, что занимает намного больше времени, чем изменение уже существующего объекта.
Для этой проблемы особенно тот факт, что при использовании списка F # тот факт, что вам нужно повторять список простых чисел каждый раз, является потерей производительности по сравнению с использованием массива.Следует также отметить, что вам не нужно генерировать список кандидатов отдельно, вы можете просто зациклить и добавить 2 на лету.Тем не менее, наибольший выигрыш в производительности, вероятно, заключается в использовании мутации для хранения ваших nextNumber
.
type prime = {BaseNumber: int; mutable NextNumber: int}
let isComposite (primes:prime list) candidate =
let rec inner primes candidate =
match primes with
| [] -> false
| p::ps ->
match p.NextNumber = candidate with
| true -> p.NextNumber <- p.NextNumber + p.BaseNumber*2
inner ps candidate |> ignore
true
| false -> inner ps candidate
inner primes candidate
let prime nth: int option =
match nth with
| 0 -> None
| 1 -> Some 2
| _ ->
let rec findPrime (primes: prime list) (candidate: int) (n: int) =
match nth - n with
| 1 -> primes
| _ -> let isC = isComposite primes candidate
if (not isC) then
findPrime ({BaseNumber = candidate; NextNumber = candidate*candidate}::primes) (candidate + 2) (n+1)
else
findPrime primes (candidate + 2) n
let p = findPrime [{BaseNumber = 3; NextNumber = 9};{BaseNumber = 5; NextNumber = 25}] 7 2
|> List.head
Some(p.BaseNumber)
. Пройдя через #time
, я получу около 500 мсек для запуска prime 10001
.Для сравнения, ваш «императивный» код занимает около 250 мс, а ваш «идоматический» код - около 1300 мс.