I've got problem with a Haskell program.
I'm trying to change [[Char]]
to [[Int]]
I've got
["2","2","1","2,2","1"]
list of char list
and I'm trying to change it to [[Int]]
[[2],[2],[1],[2,2],[1]]
I've tried
f :: [String] -> [Int]
f = map read
but it gives me
[2,2,1,*** Exception: Prelude.read: no parse
Can anybody help me with this?
A character literal in Haskell has type Char . To convert a Char to or from the corresponding Int value defined by Unicode, use toEnum and fromEnum from the Enum class respectively (or equivalently ord and chr ).
The character type Char is an enumeration whose values represent Unicode (or equivalently ISO 10646) characters. This set extends the ISO 8859-1 (Latin-1) character set (the first 256 charachers), which is itself an extension of the ASCII character set (the first 128 characters).
If the char variable contains an int value, we can get the int value by calling Character. getNumericValue(char) method. Alternatively, we can use String. valueOf(char) method.
The reason that this fails is because a string "2,2"
can not be converted to an Int
itself: this is a digit followed by a comma, followed by a digit. An Int
is parsed by an optional minus sign, followed by some digits, and some extra possibilities like hexadecimal numbers, but let us ignore these for now.
The type signature you specify for f
is however incorrect, based on the expected output. Your output type seems to be a list of lists of Int
s, so [[Int]]
. That means that you should specify f
as:
f :: [String] -> [[Int]]
f = ...
We thus need to read every String
to an [Int]
. We can not use read
directly here, since read
ing to an [Int]
expects the string to start and end with square brackets. We can however add these manually like:
f :: [String] -> [[Int]]
f = map (\s -> read ('[' : s ++ "]"))
or a point-free version:
f :: [String] -> [[Int]]
f = map (read . ('[' :) . (++ "]"))
For example:
Prelude> f ["2","2","1","2,2","1"]
[[2],[2],[1],[2,2],[1]]
readMaybe
Parsing from String
s like in the above way is of course not very "safe", since it is possible that the String
does not follow the format. We can make this more safe and use for example readMaybe :: Read a => String -> Maybe a
:
import Text.Read(readMaybe)
f :: [String] -> [Maybe [Int]]
f = map (readMaybe . ('[' :) . (++ "]"))
For example:
Prelude Text.Read> f ["2", "3;2", "4,7,3", "bla"]
[Just [2],Nothing,Just [4,7,3],Nothing]
we can omit the failed reads for example by using catMaybes :: [Maybe a] -> [a]
:
import Data.Maybe(catMaybes)
import Text.Read(readMaybe)
f :: [String] -> [[Int]]
f = catMaybes . map (readMaybe . ('[' :) . (++ "]"))
For example:
Prelude Data.Maybe Text.Read> f ["2", "3;2", "4,7,3", "bla"]
[[2],[4,7,3]]
or as @dfeuer said, we can use traverse :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)
to return an [[Int]]
result wrapped in a Just
if all parsing succeeded, and Nothing
otherwise:
import Text.Read(readMaybe)
f :: [String] -> Maybe [[Int]]
f = traverse (readMaybe . ('[' :) . (++ "]"))
For example:
Prelude Text.Read> f ["2","2","1","2,2","1"]
Just [[2],[2],[1],[2,2],[1]]
Prelude Text.Read> f ["2", "3;2", "4,7,3", "bla"]
Nothing
readEither
We can obtain an error message wrapped in a Left
in case the parsing fails by using readEither :: Read a => String -> Either String a
:
import Text.Read(readEither)
f :: [String] -> [Either String [Int]]
f = map (readEither . ('[' :) . (++ "]"))
For example:
Prelude Text.Read> f ["2", "3;2", "4,7,3", "bla"]
[Right [2],Left "Prelude.read: no parse",Right [4,7,3],Left "Prelude.read: no parse"]
and use traverse
in the same way to obtain an error message wrapped in a Left
or the complete result in a Right
:
import Text.Read(readEither)
f :: [String] -> Either String [[Int]]
f = traverse (readEither . ('[' :) . (++ "]"))
For example:
Prelude Text.Read> f ["2","2","1","2,2","1"]
Right [[2],[2],[1],[2,2],[1]]
Prelude Text.Read> f ["2", "3;2", "4,7,3", "bla"]
Left "Prelude.read: no parse"
Here, like @dfeuer says, it does not really shows much information. There are however parsers that can provide more informative parsing errors.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With