假设我有以下函数
myFunction :: Integer->Integer->Integer->Rational
myFunction n m l
| m>l = 0
| m==1 = 1 / n ** (l-1)
| m==l = (p n l 1) * ( factorial (n-1) ) / factorial (n-l)
| otherwise = (m/n) * (p n (l-1) m) + ((n-m+1)/n) p n (l-1) (m-1)
细节并不重要,关键是为了计算n=100,l=200和m=100的函数,代码需要解决(l=199,m=100)和(l=199,m=100)的问题,等等。问题是,为了返回任何需要达到l==m或m==1的值,我的问题是:GHC是否重用它已经计算过的值?
除了解决递归(在这种情况下是可能的),有没有一种方法可以改进代码,使其不重新计算值?
1条答案
按热度按时间fwzugrvs1#
GHC并不试图自动记忆函数调用的结果,因此在递归中遇到的两个单独的
p 100 199 100
调用通常需要两个单独的计算。如果你想记住电话,有两种方法。
你可以使用一个记忆库。有相当多的可用,所以最好访问Hackage package list并搜索页面“memoi”,如果你想看看有什么可用的。例如,使用memoize包,您的函数可以使用以下内容进行memoize:
这将在几秒钟内生成一个答案。它还在调用之间进行记忆,因此
main
中的其他myFunction
调用将使用以前调用的记忆结果。还有一种Haskell特有的技术,你可以构建一个数据结构来表示所有可能的(或至少是所有需要的)函数求值的结果,利用惰性来自动计算所需的结果,按照依赖顺序并且没有重复,即使数据结构在概念上是无限的。
下面是你的函数的一个版本,它从所有需要的对
(l, m)
到结果中使用了一个(有限的)Map
:这个方法在每次调用时重新生成Map,所以“记忆化”不会在调用之间共享。