我正在读取一个文件,该文件包含十六进制字节。我把它读成一个字符串,把它们映射成单个单词,然后把它们转换成十进制值。
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
中,我们可以将Nothing
s转换为用户的消息,将Just
s转换为对[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, _)]
,它会出错。