In Haskell, la valutazione lenta può essere spesso utilizzata per eseguire calcoli efficienti di espressioni scritte in modo chiaro e conciso. Tuttavia, sembra che il linguaggio stesso non fornisca abbastanza dettagli per determinare, in generale, le esigenze di tempo e spazio di un dato pezzo di codice. La situazione sembra essere mitigata, in una certa misura, dall'uso comune di ghc, che raccolgo fornisce alcune garanzie più specifiche relative alla forma debole-testa-normale. Ma se non sbaglio, l'effettiva esecuzione del codice può essere ancora abbastanza difficile da capire.
Ad esempio, utilizziamo anche il polimorfismo per esprimere le funzioni in modo generico, sempre senza sacrificare la chiarezza. Tuttavia, quando combinato con strutture ponderate, le due caratteristiche linguistiche sembrano interagire in modi che sono (per me) sorprendenti. Prendere in considerazione:
import Debug.Trace (trace)
tracePlus a b = trace (show a ++ "+" ++ show b) (a+b)
-- This lets us try small integers to see how things get evaluated.
-- Those tests can thereby reveal the asymptotic behavior of the code, without
-- needing to actually try bigger values.
class Sum a where
one :: a
add :: a -> a -> a
instance Sum Integer where
one = 1
add = tracePlus
fibSums_list :: (Sum a) => [a]
fibSums_list = one : one : zipWith add fibSums_list (tail fibSums_list)
fibS :: Int -> Integer
fibS = (fibSums_list !!)
Devo notare che funziona bene se lo compilo con ghc -O2
. Tuttavia, se eseguito in ghci
, richiede una complessità temporale esponenziale per valutare fibS
. Tuttavia, l'uso di un elenco di numeri di Fibonacci di tipo [Integer]
funziona bene pure.
Quindi, una domanda specifica che ho è: c'è un modo per riscrivere fibSums_list
e / o fibS
, in modo che mantenga l'uso della classe di tipi Sum
, ed è ancora chiaramente una generalizzazione del Sequenza di Fibonacci, ma che valuta anche efficientemente in ghci? Dove comincio?
E mi chiedo se simili insidie attendono anche nel codice compilato tramite ghc -O2
. E se sì, come si comportano gli autori del codice Haskell con quelli?
Un'altra domanda correlata è Quando è il momento giusto per ragionare sulle prestazioni in Haskell? . Penso che la mia domanda sia ancora più fondamentale; Non capisco nemmeno come fare il compito di tale ragionamento. C'è una risposta ragionevole in questo caso, ma non ho abbastanza informazioni specifiche per farmi effettivamente scrivere un fibSums_list
che funziona in ghci
, per non parlare di uno che ha una sorta di complessità temporale garantita.