Di seguito sono descritte due funzioni per trovare il valore massimo di un elenco di numeri.Istanza di funzione poco ricorsiva non a coda
mx :: (Ord a) => [a] -> a
mx [] = error "Empty list"
mx [x] = x
mx (x:xs)
| x > (mx xs) = x
| otherwise = (mx xs)
mx' (x:xs) = findMax x xs
where
findMax cmx [] = cmx
findMax cmx (x:xs) | x > cmx = findMax x xs
| otherwise = findMax cmx xs
main = do
print $ mx [1..30]
Timing il codice precedente, prima per mx'(tail-ricorsiva) e successivo per mx (non-tail-ricorsiva), abbiamo le seguenti temporizzazioni.
Lenovo-IdeaPad-Y510P:/tmp$ time ./t
30
real 0m0.002s
user 0m0.000s
sys 0m0.001s
Lenovo-IdeaPad-Y510P:/tmp$ ghc -O2 t.hs
[1 of 1] Compiling Main (t.hs, t.o)
Linking t ...
Lenovo-IdeaPad-Y510P:/tmp$ time ./t
30
real 0m6.272s
user 0m6.274s
sys 0m0.000s
Qualcuno può spiegare perché c'è una così grande differenza di prestazioni per un elenco di soli 30 elementi?
Penso che il problema di fondo è che (se ho capito bene) GHC non fa eliminazione sottoespressione comune per le chiamate ricorsive. – dfeuer
@dfeuer Che suona un po 'strano. C'è un problema aperto per questo? –
@BartekBanachewicz CSE può anche portare a prestazioni peggiori, quindi GHC è prudente nel farlo. per esempio. 'length [1..1000] + length [1..1000]' può essere eseguito in uno spazio costante, 'let l = [1..1000] in length l + length l' alloca l'intero 1000 elementi. Penso che CSE sia in qualche modo garantito in ViewPatterns, dato che non c'è modo di aggirarlo. – chi