如何将此Haskell表达式考虑在内以避免重复计算?

时间:2010-07-10 13:22:32

标签: haskell performance evaluation

我有这个功能(产生斐波那契序列):

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只计算一次?

2 个答案:

答案 0 :(得分:9)

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

答案 1 :(得分:2)

<{1>} 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))