Search code examples
haskellbytestringhaskell-lenslenses

Haskell: Changing an element at a given index in a ByteString


I'm trying to change a character at indices x and y in a matrix made of ByteStrings to a different character. Initially, I used [[Char]] to represent the matrix, so I was able to use .~ from Control.Lens.Setter to change the value, but this doesn't seem to work for [ByteString].

Is there any way to use the lens or to modify the element without unpacking the ByteString like I'm doing right now?

The code, right now, is:

render :: [[Char]] -> [Loc Int] -> [[Char]]
render maze []               = maze
render maze (Loc (x,y):locs) = render mutate locs
    where mutate = element y . element x .~ '*' $ maze

Where Loc is just:

newtype Loc a = Loc (a,a) deriving (Show,Eq,Ord)

Solution

  • This works for ByteStrings:

    import qualified Data.ByteString.Char8 as BS
    import Control.Lens
    
    -- change character at position 2 to a space (ASCII code 32)
    
    test = (BS.pack "abcdef") & ix 2 .~ 32
    

    Note that ByteStrings are really containers of Word8 values, so that's we need to use the ASCII code here.

    The ix operator works for a lot of other data structures like Text, lists, Sets, Maps, etc -- see here for more details.