I am reading a file, this file contains hexadecimal bytes. I read this into a string, I map them into single words and then I turn them into their decimal values.
main = do
args <- getArgs
contents <- readFile (head args)
let singlewords = words contents
let intContents = map readHex singlewords
When I print the output of intContents, I get:
[[(5,"")],[(0,"")],[(0,"")],[(0,"")],[(5,"")],[(0,"")],[(0,"")],[(0,"")],[(48,"")],[(28,"")],[(75,"")],[(201,"")],[(134,"")],[(0,"")],[(0,"")]]
These are the proper decimal values, but why are they paired with an empty string? and as separate nested lists? I just want the values like:
[5,0,0,0,5,...]
I tried to just do:
intContents <- readHex contents
But I still only get:
[(5," 00 00 00 05 00 00 00\n30 1C 4B C9 86 00 00")]
This just does the first term. Any help would be appreciated.
Edit
Now understanding the types readHex returns, how can I use pattern matching with my code to get just the decimal number.
Some sort of definition like this?
intContents :: [(a, b)] -> a
intContents [(a, b)] = a
or do I just put the pattern in the mapping like this?
let intContents = map ([(a, b)] (readHex singleWords)
Note: I tried both of these and just have errors I don't necessarily understand
Again any help is appreciated!
It can't be done, in general, because sometimes there will be no decimal number! For example:
So to do a good job of this task, you must decide what you want to happen in surprising cases. This is, in my opinion, the type system helping you to think about what code needs to be written.
One choice you could make would be like this: if any of the contents of the file aren't hex numbers, print a message saying so and exit without doing anything else. This is about the coarsest-grained response you could have; to accomplish this task we need only remember whether there was an error so far or not. We can do this using
Maybe; as usual with lists, the patterns we need to match are[]and_:_. So:If you write this code, and turn on warnings, you'll get told that
s'andotherResultsaren't used. And that does seem like something worth thinking about! In thes'position, a successful parse will give us an empty string; and in theotherResultsposition, a successful parse will give us an empty list. We should think about what to do in other cases -- the type system helping us again!Continuing our plan of demanding that everything go perfectly, we could expand this:
Now we get a warning saying not all cases are covered. Okay, what should happen if the
s'position orotherResultsposition are not empty? PresumablyNothingagain. So:In fact, it's simpler to put the successful case first and return
Nothingin all other cases. We can also contract the syntax sugar of[x]forx:[].Okay, we have a simpler type for reading now. If we want to gather up all the failures from a whole collection of such parses, we can use
mapM. So:Finally, in
main, we can turnNothings into a message for the user, andJusts into a continuation that does something interesting with the list of[Int]s.