更新Data.ByteString

时间:2015-11-18 22:25:16

标签: haskell bytestring

C语言提供了一种非常方便的方法来更新数组的nth元素:array[n] = new_value。我对Data.ByteString类型的理解是它提供了与uint8_t的C数组非常相似的功能 - 通过index :: ByteString -> Int -> Word8访问。似乎相反的操作 - 更新值 - 并不那么容易。

我最初的做法是使用以下方式获得的takedropsingleton函数concat

updateValue :: ByteString -> Int -> Word8 -> ByteString
updateValue bs n value = concat [take (n-1) bs, singleton value, drop (n+1) bs] 

(这是一个非常天真的实现,因为它不处理边缘情况)

使用C背景时,感觉太重了,无法调用4个函数来更新一个值。从理论上讲,操作的复杂性并不是那么糟糕:

  • take是O(1)
  • drop是O(1)
  • singleton是O(1)
  • concat是O(n),但在这里我不确定 n 是否完全是连接列表的长度,或者它是否只是,在我们的例子中,是< / LI>

我的第二种方法是向Hoogle询问具有相似类型签名的函数:ByteString -> Int -> a -> ByteString,但没有出现任何合适的内容。

我是否遗漏了一些非常明显的东西,或者更新价值真的很复杂?

我想指出,我理解ByteString是不可变的,并且更改其任何元素将导致新的ByteString实例。

编辑: 我在阅读有关Control.Lens库时发现的可能解决方案使用set镜头。以下是GHCi的概述,省略了模块名称:

> import Data.ByteString
> import Control.Lens
> let clock = pack [116, 105, 99, 107]
> clock
"tick"
> let clock2 = clock & ix 1 .~ 111
> clock2
"tock"

1 个答案:

答案 0 :(得分:3)

一种解决方案是将ByteString转换为Storable Vector,然后修改:

import Data.ByteString (ByteString)
import Data.Vector.Storable (modify)
import Data.Vector.Storable.ByteString  -- provided by the "spool" package
import Data.Vector.Storable.Mutable (write)
import Data.Word (Word8)

updateAt :: Int -> Word8 -> ByteString -> ByteString
updateAt n x s = vectorToByteString . modify inner . byteStringToVector
  where
    inner v = write v n x

请参阅spoolvector的文档。