我需要计算 foo n = maximumBy (comparing p) [1..n]
,其中 p :: Int -> Int
运行缓慢。但我知道对于所有的 n > 0
,p n < n
,并想要利用这个事实加速计算过程:从 n
开始递减计算 x
的 p x
,同时记忆当前最大值。一旦我到达一个小于或等于当前最大值的 x
,我就知道这个最大值一定是全局最大值,完成计算。
因此,我的尝试看起来像这样:
foo n = go (0, 0) n where
go (c, _) 1 = c
go (c, c') !x = if c' >= x then c else go (c2, c'2) (x-1) where
x' = p x
(c2, c'2) = if c' >= x' then (c, c') else (x, x')
这个方法可以工作,但不够优雅。因此,我正在寻找更加优美的解决方案。您有什么建议吗?
go x y n ...
,然后我会将p n
绑定到一个名称上(甚至不给编译器重新计算的机会),否则这就是我要做的。简单、清晰、高效。 - Daniel Fischerwhere
。go x y n | n == 1 || n <= y = x | pn > y = go n pn (n-1) | otherwise = go x y (n-1) where pn = p n
。 - Daniel Fischerp n
没有绑定到名称,是否会重新计算;通过优化,可能不会。但是要确保,需要查看核心代码。然而,我已经学会了永远不要盲目地信任编译器,并且引入本地绑定比查看核心代码更少的工作量,并且只要编译器甚至四分之一理智,就可以做到预期的事情,因此在这种情况下我会这样做。 - Daniel Fischer