Как я могу учесть это выражение Haskell для предотвращения повторенного вычисления?

У меня есть эта функция (производит последовательность fibonacci):

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 в a where потому что p1 и p2 не находятся в объеме. Что лучший способ состоит в том, чтобы учесть это выражение так, чтобы f только вычисляется однажды?

5
задан Don Stewart 20 April 2011 в 04:32
поделиться

2 ответа

unfoldr (\(p1, p2) -> let x = f p1 p2 in Just (x, (x, p1)) ) (0, 1)
    where f = arbitrary, possibly time-consuming function
9
ответ дан 13 December 2019 в 19:20
поделиться

в 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))
2
ответ дан 13 December 2019 в 19:20
поделиться
Другие вопросы по тегам:

Похожие вопросы: