这个失败的原因是因为字符串"2,2"本身不能转换为Int:这是一个数字后跟一个逗号,然后是一个数字。 Int 由一个可选的减号解析,后跟一些数字,以及一些额外的可能性,如十六进制数字,但现在让我们忽略这些。
根据预期的输出,您为 f 指定的类型签名不正确。您的输出类型似乎是Ints 的lists 列表,所以[[Int]]。这意味着您应该将f 指定为:
f :: [String] -> [[Int]]
f = ...
因此,我们需要读取每个String 到[Int]。我们不能在这里直接使用read,因为reading 到[Int] 期望字符串以方括号 开始和结束。但是,我们可以手动添加这些:
f :: [String] -> [[Int]]
f = map (\s -> read ('[' : s ++ "]"))
或无积分版本:
f :: [String] -> [[Int]]
f = map (read . ('[' :) . (++ "]"))
例如:
Prelude> f ["2","2","1","2,2","1"]
[[2],[2],[1],[2,2],[1]]
使用readMaybe 解析更安全
以上述方式从Strings 解析当然不是很“安全”,因为String 可能不遵循格式。我们可以让它更安全并使用例如readMaybe :: Read a => String -> Maybe a:
import Text.Read(readMaybe)
f :: [String] -> [Maybe [Int]]
f = map (readMaybe . ('[' :) . (++ "]"))
例如:
Prelude Text.Read> f ["2", "3;2", "4,7,3", "bla"]
[Just [2],Nothing,Just [4,7,3],Nothing]
我们可以省略失败的读取,例如使用catMaybes :: [Maybe a] -> [a]:
import Data.Maybe(catMaybes)
import Text.Read(readMaybe)
f :: [String] -> [[Int]]
f = catMaybes . map (readMaybe . ('[' :) . (++ "]"))
例如:
Prelude Data.Maybe Text.Read> f ["2", "3;2", "4,7,3", "bla"]
[[2],[4,7,3]]
或者如@dfeuer所说,如果全部解析成功,我们可以使用traverse :: (Applicative f, Traversable t) => (a -> f b) -> t a -> f (t b)返回包裹在Just中的[[Int]]结果,否则Nothing:
import Text.Read(readMaybe)
f :: [String] -> Maybe [[Int]]
f = traverse (readMaybe . ('[' :) . (++ "]"))
例如:
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 解析错误消息
如果使用readEither :: Read a => String -> Either String a解析失败,我们可以获得包裹在Left中的错误消息:
import Text.Read(readEither)
f :: [String] -> [Either String [Int]]
f = map (readEither . ('[' :) . (++ "]"))
例如:
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"]
并以相同的方式使用traverse 来获取包含在Left 中的错误消息或在Right 中的完整结果:
import Text.Read(readEither)
f :: [String] -> Either String [[Int]]
f = traverse (readEither . ('[' :) . (++ "]"))
例如:
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"
在这里,就像@dfeuer 所说,它并没有真正显示太多信息。然而,有些解析器可以提供更多信息的解析错误。