2010-07-10 53 views
5

我有此功能(產生Fibonacci序列):如何將這個Haskell表達式分解以避免重複計算?

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

在這裏,我注意到重複表達式,p1+p2,我想因數,以使得它僅計算一次。除了本身不是一個昂貴的計算,但對於一個更一般的版本:

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

在上述情況下,f p1 p2計算兩次(除非有一些神奇的編譯器的優化,我不知道),這可能會造成性能瓶頸如果f需要大量的計算。我不能將f p1 p2分解爲where,因爲p1p2不在範圍內。將這個表達式分解爲f只計算一次的最佳方式是什麼?

回答

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

謝謝!感謝您花時間學習像這樣的初學者問題(: – guhou 2010-07-10 13:34:43

2

Control.Arrow(&&&)可以在一些像這樣使用:

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

甚至:

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

除了在你的例子p1+p2實際上是未來p1所以你可以重寫它像

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