【问题标题】:haskell how to archive memorizehaskell如何归档记忆
【发布时间】:2017-06-25 12:08:02
【问题描述】:

我正在尝试解决 Project Euler 中的 #15,这是我的第一个解决方案 导入数据列表

type Location = (Int,Int)

boardX = 20
boardY = 20

stepBack :: Location -> [Location]
stepBack (x,y) = [(x-1,y), (x,y-1)]

legalStep :: Location -> Bool
legalStep (x,y) = x >= 0 && y >= 0

iteractStep :: Int -> [[Location]]
iteractStep 0 = [[(boardX, boardY)]]
iteractStep n = [x:y|y <- iteractStep (n-1), x<- stepBack (head y),       legalStep x]

main :: IO ()
main = putStrLn $ show $ length $ iteractStep (boardX + boardY)

这很慢,我发现有很多子问题重新计算,我试着记住子问题的答案,然后我找到了这个例子:

  memoized_fib :: Int -> Integer
  memoized_fib = (map fib [0 ..] !!)
    where fib 0 = 0
          fib 1 = 1
          fib n = memoized_fib (n-2) + memoized_fib (n-1)

我在ghci中试了一下,发现它居然能记住子问题的结果,我不明白这段代码是怎么记住结果的,看起来像

map fib [0 ..] 

是全局的,但我认为它是方法范围(只存在于每个方法调用中),为什么它可以记住结果?

【问题讨论】:

标签: haskell dynamic-programming


【解决方案1】:

memoized_fib 之所以有效,是因为它最初只是从map fib [0..] 创建一个thunk(这是懒惰,按需调用)。在随后的调用中,列表中越来越多的fib 值被计算出来,同时每个调用通过索引到列表中来查找fib 值(!!)。

如果没有列表,每次调用 fib 都会再调用两次 fib,这又会调用两次,依此类推。在算法方面,这会将 fib 从 O(n^2) 更改为 O(n )。

在没有查看 Project Euler 问题的情况下,我建议您先尝试使用另一种数据结构。在您的情况下,您可能应该尝试使用vectorarray。这些都比您当前使用的列表要快得多,实际上是一个链表。

您还可以通过将您的董事会代表更改为board :: [Int] 获得一点好处。我们直观地认为一个板具有两个维度,但它很容易实现为列表而不是列表列表。 (这是我从PAIP的一章记得的)

对于其他问题,请记住 containersunordered-containers

【讨论】:

  • 知道了,memoized_fib 就像 fibs = 1:1: zipWith (+) fibs (tail fibs),最终结果是一个列表。我还有一个问题,我只对list使用fmap和head操作,为什么vector比list快?
  • 对于head,如果有什么不同的话,我认为不会有太大的影响。 AFAIK 向量将元素彼此相邻地保存在内存中,其中链表在元素之间具有指针,因此任何遍历例如fmapvector 上应该更快。
  • 刚刚在School of Haskell看到了关于列表和向量之间效率差异的一个很好的解释
猜你喜欢
  • 2018-09-08
  • 2016-04-11
  • 2022-01-04
  • 2020-10-25
  • 2011-03-13
  • 2014-10-31
  • 1970-01-01
  • 2022-01-19
  • 1970-01-01
相关资源
最近更新 更多