How can I express this Haskell expression to avoid recalculations?

I have this function (creates a fibonacci sequence):

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

Here I notice a repeating expression p1+p2that I would like to take into account, so that it is evaluated only once. The supplement itself is not an expensive calculation, but for a more general version:

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

In the above situation, it is f p1 p2calculated twice (unless there is some optimization of the magic compiler that I do not know about), which could create a performance bottleneck if fit took a lot of calculations. I can not turn f p1 p2in where, because p1, and p2not included in the scope. What is the best way to express this expression so that it is fevaluated only once?

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

in Control.Arrowexists (&&&), which can be used something like this:

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

or even:

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

p1+p2 p1,

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

All Articles