I always run into the following error when trying to read a ByteString:
Prelude.read: no parse
Here's a sample of code that will cause this error to occur upon rendering in a browser:
factSplice :: SnapletSplice App App
factSplice = do
mbstr <- getParam "input" -- returns user input as bytestring
let str = maybe (error "splice") show mbstr
let n = read str :: Int
return [X.TextNode $ T.pack $ show $ product [1..n]]
Or perhaps more simply:
simple bs = read (show bs) :: Int
For some reason, after show bs
the resulting string includes quotes.
So in order to get around the error I have to remove the quotes then read
it.
I use the following function copied from the internet to do so:
sq :: String -> String
sq s@[c] = s
sq ('"':s) | last s == '"' = init s
| otherwise = s
sq ('\'':s) | last s == '\'' = init s
| otherwise = s
sq s = s
Then simple bs = read (sq.show bs) :: Int
works as expected.
- Why is this the case?
- What is the best way to convert a ByteString to an Int?
Show
is used to create aString
representation of something, that is useful for debugging and plain-text serialization. TheShow
typeclass is not just a fancy way of converting anything into aString
. That's whyByteString
adds quotes to the string: because it's arguably easier to read it that way when debugging or deserializing a data stream.You can use the
Data.ByteString.Char8.unpack
function to convert aByteString
to aString
, but note that this unpacks theByteString
byte-per-byte, which messes up high-value Unicode characters or other characters that are stored as more than one byte; if you want to do something other than usingread
on the result, I'd recommend converting theByteString
toText
instead, which offers more flexibility in this situation. Assuming that your encoding is UTF8 in this case (As should be the default in Snap), you can use theData.Text.Encoding.decodeUtf8
function for this. To then convert aText
value to aString
with correct Unicode symbols, you useData.Text.unpack
.Once you have a
String
, you are free toread
it as much as you want; alternatively, you can choose to read aText
value directly using the functions in theData.Text.Read
module.