Haskell 正在更新Data.ByteString中的值
C语言提供了一种非常方便的方法来更新数组的第n个元素:Haskell 正在更新Data.ByteString中的值,haskell,bytestring,Haskell,Bytestring,C语言提供了一种非常方便的方法来更新数组的第n个元素:array[n]=new\u value。我对Data.ByteString类型的理解是,它提供了一个非常类似于uint8\u t-通过index::ByteString->Int->Word8访问的C数组的功能。相反的操作——更新值——似乎并不那么容易 我最初的方法是使用take、drop和singleton函数,concat以以下方式设置: updateValue :: ByteString -> Int -> Word8 -
array[n]=new\u value
。我对Data.ByteString
类型的理解是,它提供了一个非常类似于uint8\u t
-通过index::ByteString->Int->Word8访问的C数组的功能。相反的操作——更新值——似乎并不那么容易
我最初的方法是使用take
、drop
和singleton
函数,concat
以以下方式设置:
updateValue :: ByteString -> Int -> Word8 -> ByteString
updateValue bs n value = concat [take (n-1) bs, singleton value, drop (n+1) bs]
(这是一个非常幼稚的实现,因为它不处理边缘情况)
有了C背景,调用4个函数来更新一个值感觉有点太重了。从理论上讲,操作的复杂性并没有那么糟糕:
take
is O(1)
下降
为O(1)
singleton
是O(1)
concat
是O(n),但在这里我不确定n是否是串联列表的长度,或者在我们的例子中是3
我的第二种方法是向Hoogle请求一个具有类似类型签名的函数:ByteString->Int->a->ByteString
,但没有合适的结果
我是否遗漏了一些非常明显的东西,或者更新值是否真的那么复杂
我想指出的是,我理解ByteString
是不可变的,更改它的任何元素都将导致新的ByteString
实例
编辑:
我在阅读控件.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"
一种解决方案是将ByteString
转换为可存储的向量
,然后修改:
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
有关和,请参阅文档。取决于您的最终目标。如果你真的想读入一个文件,修改一个字节,然后再把它写出来,这种方法似乎是合理的。如果您实际上要做的是修改每个字节,但每次修改一个字节,那么您可能需要map
。你能解释一下你最终想要什么吗?@MathematicalArchid我明白你的意思。我正在尝试构建一个非常小的虚拟机,并使用ByteString
作为备份内存存储。所讨论的大小是以十个字节为单位的。一条指令进入并执行它修改一个特定的内存字节,例如mov4、mem7
(这就是我们的updateValue
函数的作用)。因此,map
ping在这里不是一个选项。一个重要的补充是,在这种情况下,性能是一个值得关注的问题。如果我理解正确,这将使用4个单独的函数,其中两个只是转换。您认为在这种情况下,Data.Vector
可以作为Data.ByteString
的可行替代品吗?(为了摆脱这两种转换)@DanielLovasko我绝对认为用可变结构替换为testring
是合适的。我会比使用Vector
更进一步,例如使用STArray
并将虚拟机单步操作提升到ST
。当性能很重要时,从重复的O(n)更新到O(1)是一件很容易的事情。@DanielWagner我以前从未听说过ST
monad,但在这里使用它是完全有意义的。对于阅读本文的任何人,我强烈推荐本书开头的IRC日志。