Ho il seguente codice spesso citata per il calcolo del numero di Fibonacci n-esimo in Haskell:stile non pointfree è sostanzialmente più lento
fibonacci :: Int -> Integer
fibonacci = (map fib [0..] !!)
where fib 0 = 0
fib 1 = 1
fib n = fibonacci (n-2) + fibonacci (n-1)
Usando questo, posso fare chiamate come ad esempio:
ghci> fibonacci 1000
e ricevi una risposta quasi istantanea.
Tuttavia, se modifico il codice di cui sopra in modo che non è in stile pointfree, cioè
fibonacci :: Int -> Integer
fibonacci x = (map fib [0..] !!) x
where fib 0 = 0
fib 1 = 1
fib n = fibonacci (n-2) + fibonacci (n-1)
è sostanzialmente più lento. Nella misura in cui una chiamata come
ghci> fibonacci 1000
si blocca.
La mia comprensione era che i due codici di cui sopra erano equivalenti, ma GHCi chiede di dissentire. Qualcuno ha una spiegazione per questo comportamento?
La prima definizione è più simile a 'fibonacci = let k = map fib [0 ..] in \ x -> k !! x'. Probabilmente condivide l'elenco dei risultati invece di ricalcolarlo ogni volta. – melpomene
Mm, quindi sono contento che è questa "condivisione" (memoization) che rende il primo super veloce. Ma perché fare lo stesso per il secondo? – MadMonty
Si sta eseguendo il codice in GHCI, senza ottimizzazioni. Prova a compilare entrambe le funzioni con '-O2' e verifica se GHC è abbastanza intelligente da risolvere il tuo problema. – user2407038