如何分解这个 Haskell 表达式以避免重复计算?

发布于 2024-09-08 14:10:35 字数 561 浏览 7 评论 0原文

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

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 的最佳方法是什么?

I have this function (produces the fibonacci sequence):

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

In here, I notice a repeated expression, p1+p2, which I would like to factor so that it is only calculated once. Addition itself isn't 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, f p1 p2 is calculated twice (unless there's some magic compiler optimisation I don't know about), which could create a performance bottleneck if f required a lot of computation. I can't factor f p1 p2 into a where because p1 and p2 are not in scope. What is the best way to factor this expression so that f is only calculated once?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

箹锭⒈辈孓 2024-09-15 14:10:36
unfoldr (\(p1, p2) -> let x = f p1 p2 in Just (x, (x, p1)) ) (0, 1)
    where f = arbitrary, possibly time-consuming function
unfoldr (\(p1, p2) -> let x = f p1 p2 in Just (x, (x, p1)) ) (0, 1)
    where f = arbitrary, possibly time-consuming function
街道布景 2024-09-15 14:10:36

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))

in Control.Arrow there is (&&&) which can be used in something like this:

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

or even:

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

As well in your example p1+p2 is actually next p1 so you can rewrite it like

tail (unfoldr (\(p1, p2) -> Just (p1, (p1+p2, p1)) ) (0, 1))
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文