简体   繁体   English

在Haskell中记忆的最有效方法是什么?

[英]What's the most efficient way to memoize in Haskell?

What's the fastest way to memoize a recursive function in Haskell? 在Haskell中记忆递归函数的最快方法是什么?

Background: Recently I have been solving Project Euler problems in Haskell. 背景:最近我一直在Haskell中解决Project Euler问题。 Many require many computations of a recursively defined combinatorial or number-theoretical function, for example the Fibonacci numbers. 许多需要许多递归定义的组合或数理论函数的计算,例如斐波那契数。 Performance improves dramatically if such functions are memoized, that is, the results of the function are cached for later use. 如果这些函数被记忆,性能会大大提高,也就是说,函数的结果会被缓存以供以后使用。

I have seen many solutions to this problem. 我已经看到很多解决这个问题的方法。 The most elegant seems to be this. 最优雅的似乎就是这个。 One uses Data.IntMap (or hash tables) and the State monad. 一个使用Data.IntMap(或哈希表)和State monad。 A tree based solution suggested in this answer , and such solutions seem fairly common. 这个答案中提出了一个基于树的解决方案,这种解决方案似乎很常见。 To give another example, see this blog post . 再举一个例子,请参阅此博客文章 I've seen other solutions using built-in functions. 我见过其他使用内置函数的解决方案。 There's one in section 2 here with the fix , and further it seems that the compiler can sometimes be massaged into memoizing without additional work. 还有一个在第2节在这里fix ,并进一步似乎编译器有时可以按摩到memoizing无需额外的工作。 There's also several prebuilt solutions . 还有一些预建解决方案

I'm wondering which memoization method is fastest in practice for the kinds of functions used in Project Euler. 我想知道哪种memoization方法在Project Euler中使用的各种函数的实践中最快。 My intuition says the hashtables library is, since hash tables seem to be the preferred dictionary structure in imperative languages. 我的直觉说哈希表库是,因为哈希表似乎是命令式语言中首选的字典结构。 The purely functional tree solutions are cool, but my Googling tells me they're strictly worse than hash tables in terms of asymptotic performance. 纯粹的功能树解决方案很酷,但我的谷歌搜索告诉我,它们在渐近性能方面严格比哈希表差。

Edit 编辑

A few comments said this question is too broad to answer, and upon reflection I agree. 一些评论说这个问题太宽泛而无法回答,经过反思我同意。 So let me give two concrete examples of functions to memoize: a function that computes the n'th Fibonacci number recursively, and one that computes the Catalan numbers recursively. 因此,让我给出两个具体的memoize函数示例:一个递归计算第n个Fibonacci数的函数,以及一个递归计算加泰罗尼亚数的函数。 I would like to compute these functions many times for large n. 我想为大n计算这些函数很多次。

I'm aware there are explicit formulas for these, but let's ignore that, because the real point here is to use them to benchmark memoization techniques. 我知道这些有明确的公式,但让我们忽略它,因为这里的真正要点是使用它们来记录备忘录技术。

When Trying to find the nth fibonacci number the only numbers that you need to memoize are the two previous numbers. 当试图找到第n个斐波那契数时,你需要记住的唯一数字是前两个数字。 you can do it as a tuple like (f n-1, fn ) and on each loop update this tuple. 你可以像(f n-1,fn)这样的元组,并在每个循环上更新这个元组。 note that updating the tuple is done through pointer manipulation and is not computationally expensive. 请注意,更新元组是通过指针操作完成的,并且计算成本不高。

a cleaner and slightly smarter alternative would be: 一个更清洁,更智能的替代方案是:

fibs :: [Integer]
fibs = fibcreator 0 1
  where
    fibcreator a b = a : fibcreator b (a+b)

nth = take n fibs

But one of the best algorithms that I have seen is this: 但我见过的最好的算法之一是:

  1. let's define a matrix m = [e11 = 1,e12 =1,e21 = 1,e22 = 0] 我们定义一个矩阵m = [e11 = 1,e12 = 1,e21 = 1,e22 = 0]
  2. to get nth fibonacci number we compute m' = m ^ (n-1) 得到第n个斐波那契数,我们计算m'= m ^(n-1)
  3. e11 element in the matrix m' is the nth fibonacci number 矩阵m'中的e11元素是第n个斐波纳契数

Now what is great here is that in order to get 17 fibonacci number we can do 现在最棒的是,为了获得17个斐波纳契数,我们可以做到

m' = ((((m^2)^2)^2)^2) * m

This significantly reduces the computaion time and passively embeds the memoization within the algorithm. 这显着减少了计算时间并被动地将记忆嵌入算法中。 The punchline is that Haskell already uses this algorithm to compute the power function, so you don't need to implement it. 重点是Haskell已经使用这种算法来计算幂函数,因此您不需要实现它。 the full implementation is : 完整的实施是:

data Matrix = Matrix Integer Integer Integer Integer

instance Num Matrix where
  (*) (Matrix a11 a12 a21 a22) (Matrix b11 b12 b21 b22)
   = Matrix (a11*b11 + a12*b21) (a11*b12 + a12*b22) (a21*b11 + a22*b21) (a21*b12 + a22*b22)

fib4 :: Integer -> Integer
fib4 0 = 0
fib4 n = x
  where
    (Matrix x _ _ _) = Matrix 1 1 1 0 ^ (n-1)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 用单个系列的反转对数组进行排序的最有效方法是什么? - What's the most efficient way to sort an array with a single series of inversions? Dijkstra算法代表边缘权重的最有效方法是什么 - What is the most efficient way to represent edge weights for Dijkstra's algorithm Ruby在这种文件中搜索单词的最有效方法是什么 - What's the most efficient way to search words in this kind of file by Ruby 与Python相交的最有效方法是什么? - What's the most efficient way of intersecting to collections in Python? 在列表中查找因子的最有效方法是什么? - What's the most efficient way to find factors in a list? 编写转化表算法的最有效方法是什么 - What's the most efficient way of programming a conversion table algorithm 什么是以升序打印矢量的所有元素的最有效方法,直到它没有重复的空? - What's the most efficient way to print all elements of vector in ascending order till it's empty without duplicates? 生成子集的最有效方法是什么? - What is the most efficient way to generate subsets? 什么是最有效的字符串替换算法? - What's the most efficient algorithm for string replacing? 假设我在Python中有一个列表。 按部分将其随机化的最有效的Python方法是什么? - Suppose I had a list in Python. What's the most pythonic and efficient way to randomize it by sections?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM