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í?

Respuestas a la pregunta(4)

Su respuesta a la pregunta