The C language provides a very handy way of updating the nth
element of an array: array[n] = new_value
. My understanding of the Data.ByteString
type is that it provides a very similar functionality to a C array of uint8_t
- access via index :: ByteString -> Int -> Word8
. It appears that the opposite operation - updating a value - is not that easy.
My initial approach was to use the take
, drop
and singleton
functions, concat
etaned in the following way:
updateValue :: ByteString -> Int -> Word8 -> ByteString
updateValue bs n value = concat [take (n-1) bs, singleton value, drop (n+1) bs]
(this is a very naive implementation as it does not handle edge cases)
Coming with a C background, it feels a bit too heavyweight to call 4 functions to update one value. Theoretically, the operation complexity is not that bad:
take
is O(1)drop
is O(1)singleton
is O(1)concat
is O(n), but here I am not sure if the n is the length of the concatenated list altogether or if its just, in our case, 3.
My second approach was to ask Hoogle for a function with a similar type signature: ByteString -> Int -> a -> ByteString
, but nothing appropriate appeared.
Am I missing something very obvious, or is really that complex to update the value?
I would like to note that I understand the fact that the ByteString
is immutable and that changing any of its elements will result into a new ByteString
instance.
EDIT:
A possible solution that I found while reading about the Control.Lens
library uses the set
lens. The following is an outtake from GHCi with omitted module names:
> import Data.ByteString
> import Control.Lens
> let clock = pack [116, 105, 99, 107]
> clock
"tick"
> let clock2 = clock & ix 1 .~ 111
> clock2
"tock"