Haskell列表在映射时显示数字和空字符串



我正在读取一个文件,该文件包含十六进制字节。我把它读成一个字符串,把它们映射成单个单词,然后把它们转换成十进制值。

main = do
args <- getArgs
contents <- readFile (head args)
let singlewords = words contents
let intContents = map readHex singlewords

当我打印intContents的输出时,我得到:

[[(5,"")],[(0,"")],[(0,"")],[(0,"")],[(5,"")],[(0,"")],[(0,"")],[(0,"")],[(48,"")],[(28,"")],[(75,"")],[(201,"")],[(134,"")],[(0,"")],[(0,"")]]

这些是正确的十进制值,但为什么它们与一个空字符串配对?以及作为单独的嵌套列表?我只想要这样的值:

[5,0,0,0,5,...]

我试着做:

intContents <- readHex contents

但我仍然只得到:

[(5," 00 00 00 05 00 00 00n30 1C 4B C9 86 00 00")]

这只是第一个学期。如有任何帮助,我们将不胜感激。

编辑

现在了解了readHex返回的类型,我如何在代码中使用模式匹配来获得十进制数。

像这样的定义?

intContents :: [(a, b)] -> a
intContents [(a, b)] = a

还是像这样把模式放在映射中?

let intContents = map ([(a, b)] (readHex singleWords)

注意:我尝试了这两种方法,但都有错误,我不一定能理解

再次感谢您的帮助!

如何在代码中使用模式匹配来获得小数。

一般来说,这是不可能的,因为有时没有十进制数!例如:

> readHex "lol"
[]

因此,为了做好这项任务,你必须决定在令人惊讶的情况下你想发生什么。在我看来,这是一个类型系统,可以帮助您思考需要编写什么代码。

你可以做出这样的选择:如果文件的任何内容都不是十六进制数字,那么打印一条这样的消息,然后退出,不做任何其他事情。这是关于您可能拥有的最粗粒度的响应;为了完成这项任务,我们只需要记住到目前为止是否存在错误。我们可以使用Maybe;与列表一样,我们需要匹配的模式是[]_:_。因此:

readHexMaybe :: String -> Maybe Int
readHexMaybe s = case readHex s of
[] -> Nothing
(n, s') : otherResults -> Just n

如果您编写此代码并打开警告,您将被告知未使用s'otherResults。这似乎是值得思考的事情!在s'位置,成功解析会给我们一个空字符串;并且在otherResults位置,成功解析将给我们一个空列表。我们应该考虑在其他情况下该怎么做——类型系统再次帮助我们!

继续我们要求一切顺利的计划,我们可以扩展这一点:

readHexMaybe :: String -> Maybe Int
readHexMaybe s = case readHex s of
[] -> Nothing
(n, "") : [] -> Just n

现在我们得到一个警告,说不是所有的案件都涵盖在内。好的,如果s'位置或otherResults位置不为空,该怎么办?大概又是Nothing。因此:

readHexMaybe :: String -> Maybe Int
readHexMaybe s = case readHex s of
[] -> Nothing
(n, "") : [] -> Just n
(n, _) : _ -> Nothing

事实上,将成功案例放在第一位并在所有其他情况下返回Nothing更简单。我们还可以将[x]的语法糖契约为x:[]

readHexMaybe :: String -> Maybe Int
readHexMaybe s = case readHex s of
[(n, "")] -> Just n
_ -> Nothing

好的,我们现在有一个更简单的阅读类型。如果我们想从一整套这样的解析中收集所有的失败,我们可以使用mapM。因此:

readAllHexMaybe :: [String] -> Maybe [Int]
readAllHexMaybe = mapM readHexMaybe

最后,在main中,我们可以将Nothings转换为用户的消息,将Justs转换为对[Int]s列表进行有趣操作的延续。

main = do
args <- getArgs
fileName <- case args of
[fileName] -> return fileName
_ -> die "USAGE: ./whatever FILE"
contents <- readFile fileName
case readAllHexMaybe (words contents) of
Nothing -> die "File contained things that didn't look like hex numbers"
Just ns -> {- ... -}

readHex具有类型

readHex :: (Eq a, Num a) => ReadS a 

它又是

type ReadS a = String -> [(a, String)] 

因此,在您的示例中,readHex似乎正是按照它所承诺的去做,并解释了配对。但产出究竟意味着什么?上面链接的页面告诉我们

一个类型A的解析器,表示为一个函数,该函数接受一个String,并以(A,String(对的形式返回可能的解析器列表。

因此,在您的情况下,这些解析都会产生一个唯一的值,这就是为什么您将这些对作为列表的单个项。您可以使用以下通过模式匹配轻松提取这些值:

map ([(a,_)] -> a) 

但是,您可能需要在这个提取中投入更多的精力,因为如果您不完全匹配[(a, _)],它会出错。

相关内容

  • 没有找到相关文章