Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/unity3d/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 正在更新Data.ByteString中的值_Haskell_Bytestring - Fatal编程技术网

Haskell 正在更新Data.ByteString中的值

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 -

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 -> 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日志。