在Haskell中记忆递归函数的最快方法是什么?在Haskell中记忆最有效的方法是什么?
背景:最近我一直在解决Haskell中的项目欧拉问题。许多计算需要递归定义的组合或数理论函数,例如斐波那契数。如果这样的函数被记忆,性能会显着提高,也就是说,函数的结果被缓存供以后使用。
我见过这个问题的很多解决方案。最优雅的似乎是this.一个使用Data.IntMap(或哈希表)和状态monad。 this answer中提出了一种基于树的解决方案,这种解决方案看起来相当普遍。再举一个例子,见this blog post。我见过使用内置函数的其他解决方案。第2节here中有一个fix
,并且进一步看来,编译器有时可能是massaged into memoizing而没有额外的工作。还有几个prebuilt solutions。
我想知道在Project Euler中使用哪种函数的实践中哪种记忆方法是最快的。我的直觉说哈希表库是,因为哈希表似乎是命令式语言中的首选字典结构。单纯的功能树的解决方案是很酷,但我的谷歌搜索告诉我,他们是strictly worse than hash tables in terms of asymptotic performance.
编辑
一些评论说,这个问题太宽而不能回答,并在反思我同意。因此,让我举两个具体的memoize函数示例:递归计算第n个斐波那契数的函数,以及递归计算加泰罗尼亚数的函数。我想多次为大n计算这些函数。
我知道有这些明确的公式,但让我们忽略它,因为这里的真正意义在于使用它们来测试记忆技术。
二叉搜索树[像'IntMap'(https://github.com/haskell/containers/blob/master/Data/IntMap/Internal.hs#L347-L352)是是的,对于_asymptotic_表现来说,它比散列映射慢。渐近线不是一切,但。 'IntMap'还有其他一些理想的属性,例如避免哈希的开销,以持久方式使用时表现良好等。对于正常用法,IntMap的性能与哈希表相竞争。 –
这取决于问题。如果数组是合适的,例如当你最终必须评估一个范围内每个值的函数时,那么它们可能是最有效的选择。 –
作为附注,您链接到的最后一个堆栈溢出答案由Jon Harrop编写。 [这里](https://www.reddit.com/r/haskell/comments/4ogle3/post_about_the_disadvantages_of_functional/d4clabv/)是@sclv写的一段评论,我认为是相关的。 – Alec