Как Haskell оценивает эту функцию простых чисел?
Мне довольно сложно понять, как Хаскелл оценит это primes
функция. Это primes
Функция оценивается снова и снова, или primes
в primeFactors
функция укажет на первый primes
?
primes = 2 : filter ((==1) . length . primeFactors) [3,5..]
primeFactors n = factor n primes
where
factor n (p:ps)
| p * p > n = [n]
| n `mod` p == 0 = p : factor (n `div` p) (p:ps)
| otherwise = factor n ps
main :: IO ()
main = print $ length . take 100000 $ primes
2 ответа
primes
это просто список. Его первый элемент равен 2, а остальные элементы взяты из списка нечетных целых чисел, отфильтрованных (частично) функцией primeFactors
,
primeFactors
, тем не менее, использует primes
, Разве это не циркуляр?
Не совсем. Потому что Хаскелл ленив, primeFactors
не нужны все значения в primes
сразу, только те, которые меньше или равны квадратному корню его аргумента (p:ps
соответствует primes
, но нам нужно только ps
если p*p <= n
), и эти простые числа были найдены предыдущими звонками primeFactors
,
В качестве примера проследите первые несколько звонков primeFactors
, Для краткости пусть b = (==1) . length . primeFactors
,
primeFactors 3 == factor 3 primes
-- only unpack as much of primes as we need for the next step
== factor 3 (2:filter b [3,5..])
-- because 2*2 > 3, that's only one level
== [3]
И так, так как b [3]
верно, мы знаем, что 3 является следующим элементом primes
, То есть, primes = 2:3:filter b [5,7..]
primeFactors 5 == factor 5 primes
== factor 5 (2:3:filter b [3,5..])
-- 2*2 > 5 is false, as is 5 `mod` 2 == 0, so
== factor 5 (3:filter b [3,5..])
-- 3*3 > 5, so
== [5]
А также b [5]
верно, так 5
это следующий элемент primes
,
primeFactors 7 == factor 7 primes
== factor 7 (2:3:5:filter b [3,5..])
== factor 7 (3:5:filter b [3,5..])
-- 3*3 > 7
== [7]
А также b [7]
верно, так 7
это следующий элемент primes
, (Похоже, все добавляется в primes
не так ли? Еще один звонок primeFactors
покажет что дело не в этом)
primeFactors 9 == factor 9 primes
== factor 9 (2:3:5:7:filter b [3,5..])
-- 2*2 > 9 and 9 `mod` 2 == 0 are false
== factor 9 (3:5:7:filter b [3,5..])
-- 3*3 > 9 is false, but 9 `mod` 3 == 0 is true, so
== 3 : factor (9 `div` 3) (3:5:7:filter b [3,5..])
== 3 : factor 3 (3:5:7:filter b [3,5..])
-- 3*3 > 3 is false, but 3 `mod` 3 == 0, so
== 3 : [3] == [3,3]
Но с тех пор b [3,3]
ложно, 9
не является элементом primes
, Итак, теперь у нас есть
primes = 2:3:5:7:filter b [3,5..])
Прослеживать это долгий и утомительный процесс, но вы должны почувствовать, что primes
всегда остается "впереди" primeFactors
; элементы primes
тот primeFactors
нужды всегда определялись предыдущими звонками primeFactors
,
как Haskell оценит эту функцию простых чисел?
Как показывает ваш код, он выводит первые 100000 простых чисел, так как primes
работать?
Во-первых, для генерации первого простого числа это просто, просто первый элемент списка:
2 : filter ((==1) ...
то есть 2
и для следующего нам нужно подать заявку primeFactors
функционировать как
primeFactors 3 = factor 3 primes
и теперь может запутать кого-то, кто плохо знаком с Haskell, как оценить primes
в выражении выше? Ответ в том, что это просто список с элементами [2,...]
, благодаря ленивой оценке, теперь нам не нужно оценивать все простые числа списка, сгенерированного primes
функция. нам просто нужно оценить следующий и посмотреть, что получится. Итак, мы получаем 2
и вышеприведенное выражение становится:
primeFactors 3 = factor 3 [2,..]
а также
factor 3 (2:ps) | 2 * 2 > 3 = [3]
Так, primeFactors 3
Retrun [3]
так что
2: filter ((==1) . length . primeFactors) 3 = [2,3]
теперь мы успешно генерируем 2 простых числа, но нам нужно 100000, а как насчет следующего? Очевидно, мы применяем 5
к выражению ниже:
2: filter ((==1) . length . primeFactors) 5
повторяет процедуру, как указано выше:
primeFactors 5 = factor 5 [2,3,..]
и на этот раз у нас есть 2 элемента в списке:
factor 5 [2,3..]
а также
factor 5 [2,3..] | otherwise = factor 5 [3,...]
а также
factor 5 [3,...] | 3 * 3 > 5 = [5]
и повторять снова и снова, пока не будет сгенерировано 100000 простых чисел, и снова, из-за ленивых вычислений, нам не нужно простое число 100001, поэтому вычисление останавливается и выводится результат.