Haskell:使用O(1)追加和O(1)索引的Datastruture?

Pau*_*aul 8 haskell vector data-structures

我在Haskell中寻找一种支持快速索引和快速追加的数据结构.这是针对由递归引起的memoization问题.

从矢量在c ++中工作的方式(这是可变的,但在这种情况下应该无关紧要)它似乎是不可变的向量与(摊销)O(1)追加和O(1)索引应该是可能的(好吧,它不是,看到这个问题的评论).这在Haskell中是不可能的,还是应该使用Data.Sequence,它有(AFAICT无论如何)O(1)追加和O(log(min(i,ni)))索引?

在一个相关的说明中,作为一个Haskell新手,我发现自己渴望一个实用,简洁的Haskell数据结构指南.理想情况下,这将对最实用的数据结构以及性能特征和指向Haskell库的指针进行相当全面的概述.似乎有很多信息,但我发现它有点分散.我问得太多了吗?

ham*_*mar 10

对于简单的memoization问题,您通常希望构建一次表,然后不再修改它.在这种情况下,您可以避免担心附加,而是将memoization表的构造视为一个操作.

一种方法是利用惰性求值,并在构造它时参考表格.

import Data.Array
fibs = listArray (0, n-1) $ 0 : 1 : [fibs!(i-1) + fibs!(i-2) | i <- [2..n-1]]
  where n = 100
Run Code Online (Sandbox Code Playgroud)

当表的元素之间的依赖关系使得很难提出一个提前评估它们的简单顺序时,此方法特别有用.但是,它需要使用盒装数组或向量,这可能会使这种方法由于额外的开销而不适合大型表.

对于未装箱的向量,您可以使用这样的操作constructN,以纯粹的方式构建表,同时使用下面的变异使其高效.它通过给你传递一个到目前为止构造的向量前缀的不可变视图的函数来做到这一点,然后你可以用它来计算下一个元素.

import Data.Vector.Unboxed as V
fibs = constructN 100 f
  where f xs | i < 2 = i
             | otherwise = xs!(i-1) + xs!(i-2)
             where i = V.length xs
Run Code Online (Sandbox Code Playgroud)

  • @hammar谢谢你的回答.我不太确定我的问题是否足够简单以适应这种方法(它使用memoization fixpoint函数+一个函数,它给出了终端状态+一个更新规则,它采用了(可能)自己的memoized版本).我不得不考虑一下. (2认同)

Dan*_*ner 9

如果内存服务,C++向量实现为具有边界和大小信息的数组.当插入会增加超出大小的边界时,大小会加倍.这是O(1)时间插入的摊销(不是你声称的O(1)),并且可以使用Array类型在Haskell中模拟得很好,可能是合适的IOST前置的.

  • 是的,它是摊销的O(1),我知道,忘记提及它.我会检查数组,你是否有一个很好的资源来与IO或ST一起学习它?如果可能的话,我希望代码是纯粹的,并且没有ST monad的经验. (2认同)
  • 这段代码不会是纯粹的.那是不可能的.可变性与不可变性_does_有所不同. (2认同)
  • @Paul我已经完成了编写一个执行此操作的库的第一个1%[并将其粘贴在hpaste上](http://hpaste.org/68041).在我将其上传到hpaste后,我放弃了所留下的任何版权.您可能希望扩展API,更改名称,基准测试以及完成所有这些好东西,但它至少应该让您在"ST"monad中进行编程,以便开始使用. (2认同)

tru*_*ity 7

看看这个,以便更明智地选择应该使用的内容.

但简单的说法是,如果你想要相当于C++向量,请使用Data.Vector.