在 Haskell 中,我有一个容器,例如:
data Container a = Container { length :: Int, buffer :: Unboxed.Vector (Int,a) }
这个容器是一棵扁平的树。它的访问器通过向量(!)
执行二进制 ( log(N)
) 搜索,以便找到存储的正确存储桶index
。
(!) :: Container a -> Int -> a
container ! index = ... binary search ...
由于连续访问可能在同一个桶中,因此可以通过以下方式进行优化:
if `index` is on the the last accessed bucket, skip the search
棘手的一点是last accessed bucket
零件。在 JavaScript 中,我只是不纯地修改了容器对象上的隐藏变量。
function read(index,object){
var lastBucket = object.__lastBucket;
// if the last bucket contains index, no need to search
if (contains(object, lastBucket, index))
var bucket = lastBucket;
// if it doesn't
else {
// then we search the bucket
var bucket = searchBucket(index,object);
// And impurely annotate it on the container, so the
// next time we access it we could skip the search.
container.__lastBucket = bucket;
}
return object.buffer[bucket].value;
}
由于这只是一种优化,并且结果与所采用的分支无关,因此我相信它不会破坏引用透明度。在 Haskell 中,如何不纯地修改与运行时值相关的状态?
~
我想到了两种可能的解决方案。
一个全局的、可变的 hashmap 链接指向该
lastBucket
值的指针,并使用 unsafePerformIO 对其进行写入。但是我需要一种方法来获取对象的运行时指针,或者至少是某种唯一的 id(如何?)。在 , 中添加一个额外的字段
Container
,lastBucket :: Int
并以某种方式在 中不纯地修改它(!)
,并认为该字段是内部的(因为它显然破坏了引用透明度)。