Проблема, которую описывает компилятор, заключается в том, что вы применяете несовместимые операции к одному и тому же типу: mod
требует Integral a
, sqrt
требует Floating a
, и ни один тип не удовлетворяет обоим. Вы можете обойти это, используя преобразования типов, такие как fromIntegral
и ceiling
, но вы должны быть осторожны, чтобы избежать ошибок округления. Для теста я удалил ограничение типа и использовал m = ceiling $ sqrt $ fromIntegral n
, что привело к выводу типа isPrimeSqrt :: Integral a => a -> Bool
.
Другой подход состоит в том, чтобы рассмотреть причину возникновения конфликта и искать другие решения. Причина sqrt
состоит в том, чтобы создать оптимизированную точку остановки для теста. Можем ли мы найти эту точку остановки другим способом?
Как оказалось, хотя деление стоит дорого, оно часто дает два результата: частное и остаток. С mod
вы ищете последнее, но у нас есть divMod
и quotRem
, которые производят оба. Так что, возможно, стоит попробовать, если это заметно медленнее, чем простой mod
тест ( результаты теста , по сравнению [2..]
против [2..m]
).
isPrime n = (n > 1) && null (filter isFactor (takeWhile notTooHigh divisors))
where notTooHigh (divisor,quotient,_) = divisor <= quotient
isFactor (_,_,remainder) = remainder == 0
divisors = [(divisor,quotient,remainder) |
divisor <- 2:[3,5..],
let (quotient,remainder) = quotRem n divisor]