Por que esse algoritmo haskell simples é tão lento?

lerta de Spoiler: está relacionado aProblem 14 do Projeto Euler.

O código a seguir leva cerca de 15s para ser executado. Eu tenho uma solução Java não recursiva que é executada em 1s. Acho que devo conseguir esse código muito mais próximo diss

import Data.List

collatz a 1  = a
collatz a x
  | even x    = collatz (a + 1) (x `div` 2)
  | otherwise = collatz (a + 1) (3 * x + 1)

main = do
  print ((foldl1' max) . map (collatz 1) $ [1..1000000])

Eu criei um perfil com+RHS -p e percebeu que a memória alocada é grande e cresce à medida que a entrada aumenta. Paran = 100,000 1gb está alocado (!), Paran = 1,000,000 13gb (!!) está alocado.

Então de novo,-sstderr mostra que, embora muitos bytes tenham sido alocados, o uso total de memória foi de 1 mb e a produtividade foi de 95% +, portanto, talvez 13 gb sejam negativo

Eu consigo pensar em algumas possibilidades:

Algo não é tão rigoroso quanto precisa. Eu já descobrifoldl1', mas talvez eu precise fazer mais? É possível marcarcollatz tão rigoroso (isso faz algum sentido?

collatz não está otimizando a chamada final. Eu acho que deveria ser, mas não sei como confirmar.

O compilador não está fazendo algumas otimizações, acho que deveria - por exemplo, apenas dois resultados decollatz precisa estar na memória a qualquer momento (máximo e atual)

Alguma sugestão

Esta é praticamente uma duplicata dePor que essa expressão Haskell é tão lenta?, embora observarei que a solução Java rápida não precisa executar nenhuma memorização. Existem maneiras de acelerar isso sem precisar recorrer a isso?

Para referência, aqui está minha saída de criação de perfil:

  Wed Dec 28 09:33 2011 Time and Allocation Profiling Report  (Final)

     scratch +RTS -p -hc -RTS

  total time  =        5.12 secs   (256 ticks @ 20 ms)
  total alloc = 13,229,705,716 bytes  (excludes profiling overheads)

COST CENTRE                    MODULE               %time %alloc

collatz                        Main                  99.6   99.4


                                                                                               individual    inherited
COST CENTRE              MODULE                                               no.    entries  %time %alloc   %time %alloc

MAIN                     MAIN                                                   1           0   0.0    0.0   100.0  100.0
 CAF                     Main                                                 208          10   0.0    0.0   100.0  100.0
  collatz                Main                                                 215           1   0.0    0.0     0.0    0.0
  main                   Main                                                 214           1   0.4    0.6   100.0  100.0
   collatz               Main                                                 216           0  99.6   99.4    99.6   99.4
 CAF                     GHC.IO.Handle.FD                                     145           2   0.0    0.0     0.0    0.0
 CAF                     System.Posix.Internals                               144           1   0.0    0.0     0.0    0.0
 CAF                     GHC.Conc                                             128           1   0.0    0.0     0.0    0.0
 CAF                     GHC.IO.Handle.Internals                              119           1   0.0    0.0     0.0    0.0
 CAF                     GHC.IO.Encoding.Iconv                                113           5   0.0    0.0     0.0    0.0

And -sstderr:

./scratch +RTS -sstderr 
525
  21,085,474,908 bytes allocated in the heap
      87,799,504 bytes copied during GC
           9,420 bytes maximum residency (1 sample(s))          
          12,824 bytes maximum slop               
               1 MB total memory in use (0 MB lost due to fragmentation)  

  Generation 0: 40219 collections,     0 parallel,  0.40s,  0.51s elapsed
  Generation 1:     1 collections,     0 parallel,  0.00s,  0.00s elapsed

  INIT  time    0.00s  (  0.00s elapsed)
  MUT   time   35.38s  ( 36.37s elapsed)
  GC    time    0.40s  (  0.51s elapsed)
  RP    time    0.00s  (  0.00s elapsed)  PROF  time    0.00s  (  0.00s elapsed)
  EXIT  time    0.00s  (  0.00s elapsed)
  Total time   35.79s  ( 36.88s elapsed)  %GC time       1.1%  (1.4% elapsed)  Alloc rate    595,897,095 bytes per MUT second

  Productivity  98.9% of total user, 95.9% of total elapsed

E solução Java (não a minha, retirada dos fóruns do Project Euler com a memoização removida):

public class Collatz {
  public int getChainLength( int n )
  {
    long num = n;
    int count = 1;
    while( num > 1 )
    {
      num = ( num%2 == 0 ) ? num >> 1 : 3*num+1;
      count++;
    }
    return count;
  }

  public static void main(String[] args) {
    Collatz obj = new Collatz();
    long tic = System.currentTimeMillis();
    int max = 0, len = 0, index = 0;
    for( int i = 3; i < 1000000; i++ )
    {
      len = obj.getChainLength(i);
      if( len > max )
      {
        max = len;
        index = i;
      }
    }
    long toc = System.currentTimeMillis();
    System.out.println(toc-tic);
    System.out.println( "Index: " + index + ", length = " + max );
  }
}

questionAnswers(3)

yourAnswerToTheQuestion