Haskell 有效地替换二进制对象的一部分

Haskell 有效地替换二进制对象的一部分,haskell,Haskell,我的目标是高效地覆盖blob的几个部分,同时保留其整体内容 结构质朴。为此,我编写了以下函数: replace :: ByteString -> Int -> ByteString -> ByteString replace source offset replacement = prefix <> replacement <> suffix where prefix = ByteString.take offset source

我的目标是高效地覆盖blob的几个部分,同时保留其整体内容 结构质朴。为此,我编写了以下函数:

replace :: ByteString -> Int -> ByteString -> ByteString
replace source offset replacement = prefix <> replacement <> suffix
  where
    prefix = ByteString.take offset source 
    suffix = ByteString.drop (offset + ByteString.length replacement) source

fix :: Int -> ByteString -> ByteString -> ByteString
fix offset replacement source = replace source offset replacement
不幸的是,
=
append
是线性时间,因此这些函数也是线性时间。拥有 只要知道更换的是被更换的部分,我们当然可以做到 更好


如果我们能够在时间上以少于替换次数的线性替换多个部分,我会特别高兴。

给定的
concat
在列表的大小上是线性的,并且
take
drop
都是O(1),这可能是最好的:

replace source offset replacement = 
  concat [ take offset source
         , replacement
         , drop n source
         ] 
  where n = offset + length replacement
对于任意数量的替换:

replacemany :: [(Int, ByteString)] -> ByteString -> ByteString
replacemany wss bs = foldr f bs wss where
  f (l, ws) bs = replace bs l ws

你说的线性是指与草堆成比例的线性,而不是与针成比例的线性,对吗?好的,只要您生成一个修改了一些字节的副本,您就无法避免这种情况。如果你想要破坏性的就地替换,你可能需要圣莫纳德。@SimonShine如果你能写一个答案,说明如何使用圣莫纳德进行替换,那就太好了。据我所知,我们将不得不将ByteString视为数组,我不确定它在道德上是否正确,因为底层表示可能会改变,在这里使用普通数组是否合理;做一些快速的研究,我会尝试结合和,但在ByteString和STArray之间进行选择是有成本的。或者,似乎可以让您直接在ByTestRing上执行此操作。不过,我从来没有尝试过这样的事情。如果你做了很多替换,考虑转换为懒惰字节串(对于CONTAT是固定的时间)。对于绝对最佳性能,您最好的办法是复制字节串,然后在副本的基础外存PTR上做一个可变的替换。我已经从编写Haskell数据库类型的东西到C++中的科学计算。C++没有GC,这意味着它不能做持久的数据结构(例如,代码> [] /代码>或<代码>数据。结果是存在大量的复制,即使您不打算使用纯函数式编程(我就是这么做的)。但是现在我对我的程序进行了大量的分析,我发现大部分的复制都没有出现,如果出现了,那么问题就不是O(n)复制步骤本身,而是O(1)分配/释放步骤。好吧,这肯定是非常可读的,很好。但我仍然希望有一个性能更好的解决方案。另外,我想知道您如何将其扩展到使用多个偏移替换对。当然有一个折叠:-)如果我是正确的,如果您考虑到非严格性,这是摊销O(1)。我不确定我是否看到它应该如何进行。你介意把你的想法编辑成答案吗?特别是在摊销O(1)部分,我认为ByteString类型在某种程度上像列表一样工作,因为当您实际使用列表时,您只需支付concat的成本,但后来我查看了源代码,它使用的是memcpy,所以现在我不太确定。总之,刚刚添加了一些代码,希望对您有所帮助。
replacemany :: [(Int, ByteString)] -> ByteString -> ByteString
replacemany wss bs = foldr f bs wss where
  f (l, ws) bs = replace bs l ws