2010-07-10 10 views
5

Ho questa funzione (produce la sequenza Fibonacci):Come posso considerare questa espressione di Haskell per evitare calcoli ripetuti?

unfoldr (\(p1, p2) -> Just (p1+p2, (p1+p2, p1))) (0, 1) 

Qui, noto un'espressione ripetuta, p1+p2, che desidero fattore modo che è calcolato soltanto una volta. Inoltre per sé non è un calcolo costoso, ma per una versione più generale:

unfoldr (\(p1, p2) -> Just (f p1 p2, (f p1 p2, p1))) (0, 1) 
    where f = arbitrary, possibly time-consuming function 

Nella situazione di cui sopra, f p1 p2 viene calcolata due volte (a meno che non ci sia qualche ottimizzazione del compilatore magia che non lo so), che potrebbe creare un collo di bottiglia per le prestazioni se f richiedeva un sacco di calcoli. Non è possibile calcolare f p1 p2 in un where perché p1 e p2 non rientrano nell'ambito. Qual è il modo migliore per calcolare questa espressione in modo che f venga calcolato solo una volta?

risposta

9
unfoldr (\(p1, p2) -> let x = f p1 p2 in Just (x, (x, p1))) (0, 1) 
    where f = arbitrary, possibly time-consuming function 
+0

grazie! grazie per aver dedicato del tempo a domande per principianti come questo (: – guhou

2

in Control.Arrow c'è (&&&) che può essere utilizzato in qualcosa di simile:

unfoldr (\(p1,p2) -> (Just . (id &&& flip (,) p1)) (p1+p2)) (0,1) 

o anche:

unfoldr (Just . (fst &&& id) . (uncurry (+) &&& fst)) (0,1) 

Come pure nel tuo esempio p1+p2 è in realtà prossima p1 in modo da può riscriverlo come

tail (unfoldr (\(p1, p2) -> Just (p1, (p1+p2, p1))) (0, 1))