我有这个功能(产生斐波那契序列):
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
,因为p1
和p2
不在范围内。对此表达式进行分解的最佳方法是什么,以便f
只计算一次?
答案 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)
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))