简体   繁体   English

haskell [[Char]]到[[Int]]

[英]haskell [[Char]] to [[Int]]

I've got problem with a Haskell program. 我遇到了Haskell程序的问题。 I'm trying to change [[Char]] to [[Int]] I've got 我正试图改变[[Char]][[Int]]我有

["2","2","1","2,2","1"] 

list of char list and I'm trying to change it to [[Int]] char列表列表,我正在尝试将其更改为[[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 [2,2,1,***例外:Prelude.read:没有解析

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. 这种失败的原因是因为字符串"2,2"无法转换为Int本身:这是一个数字,后跟一个逗号,后跟一个数字。 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. Int由可选的减号解析,后跟一些数字,以及一些额外的可能性,如十六进制数,但让我们暂时忽略它们。

The type signature you specify for f is however incorrect, based on the expected output. 但是,根据预期的输出,为f指定的类型签名是不正确的。 Your output type seems to be a list of lists of Int s, so [[Int]] . 您的输出类型似乎是Int的列表列表 ,因此[[Int]] That means that you should specify f as: 这意味着您应该将f指定为:

f :: [String] -> [[Int]]
f = ...

We thus need to read every String to an [Int] . 因此,我们需要将每个String读取到[Int] We can not use read directly here, since read ing to an [Int] expects the string to start and end with square brackets . 我们不能直接在这里使用read ,因为read [Int]期望字符串以方括号开头和结尾。 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]]

Towards safer parsing with readMaybe 使用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. 像上面那样从String解析当然不是很“ 安全 ”,因为String可能不遵循格式。 We can make this more safe and use for example readMaybe :: Read a => String -> Maybe a : 我们可以使这更安全,并使用例如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] : 我们可以省略失败的读取,例如使用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 -> fb) -> ta -> f (tb) to return an [[Int]] result wrapped in a Just if all parsing succeeded, and Nothing otherwise: 或者如@dfeuer所说,我们可以使用traverse :: (Applicative f, Traversable t) => (a -> fb) -> ta -> f (tb)返回包含在Just[[Int]]结果所有解析都成功了,否则Nothing

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

Parse with error messages with readEither 使用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 : 我们可以通过使用readEither :: Read a => String -> Either String a获取解析失败的情况下包含在Left中的错误消息:

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 : 并以相同的方式使用traverse来获取包含在Left的错误消息或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. 在这里,就像@dfeuer所说,它并没有真正显示太多信息。 There are however parsers that can provide more informative parsing errors. 但是,解析器可以提供更多信息性的解析错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM