Haskell estilo / eficiencia
Entonces estaba trabajando en una forma de generar primos perezosamente, y se me ocurrieron estas tres definiciones, que funcionan de manera equivalente, solo comprobando si cada nuevo entero tiene un factor entre todos los primos anteriores:
primes1 :: [Integer]
primes1 = mkPrimes id [2..]
where mkPrimes f (x:xs) =
if f (const True) x
then
let g h y = y `mod` x > 0 && h y in
x : mkPrimes (f . g) xs
else
mkPrimes f xs
primes2 :: [Integer]
primes2 = mkPrimes id (const True) [2..]
where mkPrimes f f_ (x:xs) =
if f_ x
then
let g h y = y `mod` x > 0 && h y in
x : mkPrimes (f . g) ( f $ g $ const True) xs
else
mkPrimes f f_ xs
primes3 :: [Integer]
primes3 = mkPrimes [] [2..]
where mkPrimes ps (x:xs) =
if all (\p -> x `mod` p > 0) ps
then
x : mkPrimes (ps ++ [x]) xs
else
mkPrimes ps xs
Así que me pareceprimes2
debería ser un poco más rápido queprimes1
, ya que evita volver a calcularf_ = f (const True)
por cada entero (que yopensa requiere un trabajo en el orden del número de números primos que hemos encontrado hasta ahora), y solo lo actualiza cuando encontramos un nuevo número primo.
Solo de pruebas no científicas (ejecutandotake 1000
en ghci) parece queprimes3
corre más rápido queprimes2
.
Debo sacar una lección de esto y asumir que si puedo representar una función como una operación en una matriz, debería implementarla de la última manera para mayor eficiencia, o hay algo más aquí?