5

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

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 p2where因为p1并且p2不在范围内。考虑这个表达式的最佳方法是什么,以便f只计算一次?

4

2 回答 2

9
unfoldr (\(p1, p2) -> let x = f p1 p2 in Just (x, (x, p1)) ) (0, 1)
    where f = arbitrary, possibly time-consuming function
于 2010-07-10T13:24:35.573 回答
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))
于 2010-07-10T13:44:14.033 回答