7

I implemented function that reads ByteString and converts it in hex format. E.g. given "AA10" it converts it to [170, 16]

import qualified Data.ByteString.Lazy as BSL
import qualified Data.ByteString.Internal as BS (w2c)

rHex :: BSL.ByteString -> BSL.ByteString
rHex bs
    | BSL.null bs = BSL.empty
    | BSL.null rest' = fromHex c1 `BSL.cons` BSL.empty
    | otherwise = rChunk c1 c2 `BSL.cons` rHex rest
          where (c1, rest') = (BSL.head bs, BSL.tail bs)
                (c2, rest) = (BSL.head rest', BSL.tail rest')
                rChunk c1 c2 = (fromHex c1) * 16 + fromHex c2
fromHex = fromIntegral . digitToInt . BS.w2c

But than I realized that I need same function but for simple ByteString, not Lazy. The only approach I came to is something like this:

import qualified Data.ByteString.Lazy as BSL
import qualified Data.ByteString as BS
import qualified Data.ByteString.Internal as BS (w2c)

rHex' funcs@(null, empty, cons, head, tail, fromHex) bs
    | null bs = empty
    | null rest' = fromHex c1 `cons` empty
    | otherwise = rChunk c1 c2 `cons` rHex' funcs rest
          where (c1, rest') = (head bs, tail bs)
                (c2, rest) = (head rest', tail rest')
                rChunk c1 c2 = (fromHex c1) * 16 + fromHex c2

fromHex = fromIntegral . digitToInt . BS.w2c

rHexBSL :: BSL.ByteString -> BSL.ByteString
rHexBSL = rHex' (BSL.null, BSL.empty, BSL.cons, BSL.head, BSL.tail, fromHex)

rHexBS :: BS.ByteString -> BS.ByteString
rHexBS = rHex' (BS.null, BS.empty, BS.cons, BS.head, BS.tail, fromHex)

So I pass all needed functions directly in rHex' in functions rHexBSL rHexBS. Is there more Haskell way to make a common function for Bytestring and Bytestring.Lazy? Maybe create type class or something?

1
  • Sorry for offtop. I'd love to learn Haskell. What would you suggest to read? Commented Feb 6, 2014 at 22:08

3 Answers 3

3

I would simplify this by working with [Word8] and using pack and unpack for each type of ByteString to get what you want -- e.g.:

toHex :: Word8 -> Word8 -> Word8
toHex a b = (fromHex a) * 16 + fromHex b

hexify :: [Word8] -> [Word8] -> [Word8]
hexify (a:b:cs) = toHex a b : hexify cs
hexify [b]      = toHex 0 b
hexify []       = []

rHexBSL :: BSL.ByteString -> BSL.ByteString
rHexBSL = BSL.pack . hexify . BSL.unpack

rHexBS :: BS.ByteString -> BS.ByteString
rHexBS = BS.pack . hexify . BS.unpack

And I think doing it this way has a good chance of enabling fusion to make the operations efficient.

That said, it is instructive to see how Bryan does it in his base16-bytestring` package.

Sign up to request clarification or add additional context in comments.

2 Comments

I like this solution. But it seems that working with [Word8] instead of ByteString is much easier in almost all cases.
I have a feeling that the [Word8] view is the best when you are treating the ByteString as a list/stream of characters. But ByteString's also allow random access which doesn't mesh very well with this approach.
3

You can always use the toStrict and fromStrict functions from Data.ByteString.Lazy to convert back and forth between strict and lazy types. In this particular case:

rHexBS = BSL.toStrict . hHexBSL . BSL.fromStrict

1 Comment

Agree, this solution is much more elegant than my one.
0

There is a class to hand in the lens package http://hackage.haskell.org/package/lens-4.0.1/docs/Data-ByteString-Lens.html#v:packedBytes . So given user5402's code for hexify, which I guess should be

 hexify :: [Word8] -> [Word8]
 hexify (a:b:cs) = toHex a b : hexify cs
 hexify [b]      = [toHex 0 b]
 hexify []       = []

you will find (with Control.Lens.under also in scope) that you can write

 rHex :: IsByteString b => b -> b 
 rHex = under packedBytes hexify

and do various other things like that. It might be more trouble than it's worth; I mention it because a suitable class is there. under packedBytes f just encodes the tiresome pack . f . unpack business, but covers both senses of pack.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.