我的 Haskell 程序有问题。
我正在尝试更改 [[Char]]
至 [[Int]]
我有
["2","2","1","2,2","1"]
字符列表列表
我正在尝试将其更改为
[[Int]]
[[2],[2],[1],[2,2],[1]]
我试过了
f :: [String] -> [Int]
f = map read
但它给了我
[2,2,1,*** Exception: Prelude.read: no parse
有人可以帮我解决这个问题吗?
最佳答案
失败的原因是因为字符串 "2,2"
无法转换为 Int
本身:这是一个数字后跟一个逗号,后跟一个数字。安 Int
由一个可选的减号解析,后跟一些数字,以及一些额外的可能性,如十六进制数字,但让我们暂时忽略这些。
您为 f
指定的类型签名然而,根据预期的输出,这是不正确的。您的输出类型似乎是 Int
的列表列表s,所以[[Int]]
.这意味着您应该指定 f
作为:
f :: [String] -> [[Int]]
f = ...
因此,我们需要阅读每个
String
到 [Int]
.我们不能使用 read
直接在这里,因为 read
联系 [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
实现更安全的解析解析自
String
像上面的方式当然不是很“安全”,因为有可能是 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)
返回 [[Int]]
结果包裹在 Just
中如果所有解析都成功,则 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
解析错误消息我们可以获得包裹在
Left
中的错误信息。如果使用 readEither :: Read a => String -> Either String a
解析失败: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 所说的,它并没有真正显示太多信息。然而,有一些解析器可以提供更多信息丰富的解析错误。
关于list - haskell [[Char]] 到 [[Int]],我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56116208/