ale*_*ekq 4 int haskell list char
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"]
Run Code Online (Sandbox Code Playgroud)
list of char list
and I'm trying to change it to [[Int]]
[[2],[2],[1],[2,2],[1]]
Run Code Online (Sandbox Code Playgroud)
I've tried
f :: [String] -> [Int]
f = map read
Run Code Online (Sandbox Code Playgroud)
but it gives me
[2,2,1,*** Exception: Prelude.read: no parse
Can anybody help me with this?
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 Ints, so [[Int]]. That means that you should specify f as:
f :: [String] -> [[Int]]
f = ...Run Code Online (Sandbox Code Playgroud)
We thus need to read every String to an [Int]. We can not use read directly here, since reading 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 ++ "]"))Run Code Online (Sandbox Code Playgroud)
or a point-free version:
f :: [String] -> [[Int]]
f = map (read . ('[' :) . (++ "]"))Run Code Online (Sandbox Code Playgroud)
For example:
Prelude> f ["2","2","1","2,2","1"]
[[2],[2],[1],[2,2],[1]]
Run Code Online (Sandbox Code Playgroud)
readMaybeParsing from Strings 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 . ('[' :) . (++ "]"))Run Code Online (Sandbox Code Playgroud)
For example:
Prelude Text.Read> f ["2", "3;2", "4,7,3", "bla"]
[Just [2],Nothing,Just [4,7,3],Nothing]
Run Code Online (Sandbox Code Playgroud)
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 . ('[' :) . (++ "]"))Run Code Online (Sandbox Code Playgroud)
For example:
Prelude Data.Maybe Text.Read> f ["2", "3;2", "4,7,3", "bla"]
[[2],[4,7,3]]
Run Code Online (Sandbox Code Playgroud)
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 . ('[' :) . (++ "]"))Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
readEitherWe 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 . ('[' :) . (++ "]"))Run Code Online (Sandbox Code Playgroud)
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"]
Run Code Online (Sandbox Code Playgroud)
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 . ('[' :) . (++ "]"))Run Code Online (Sandbox Code Playgroud)
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"
Run Code Online (Sandbox Code Playgroud)
Here, like @dfeuer says, it does not really shows much information. There are however parsers that can provide more informative parsing errors.