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

Haskell list has is showing number and empty string when mapping

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

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 00\n30 1C 4B C9 86 00 00")]

这只是第一个学期。任何帮助将不胜感激。

编辑

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

像这样的定义?

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

还是像这样将模式放入映射中?

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

注意:我尝试了这两个,只是出现了我不一定理解的错误

再次感谢您的帮助!

readHex 具有类型

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

这又是(参见 here

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

所以 readHex 在你的例子中似乎完全按照它承诺的去做并解释了这些对。但是输出到底是什么意思呢?上面链接的页面告诉我们

A parser for a type a, represented as a function that takes a String and returns a list of possible parses as (a,String) pairs.

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

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

但是您可能需要在提取过程中多花点功夫,因为如果您不完全匹配 [(a, _)].

就会出错

how can I use pattern matching with my code to get just the decimal number.

一般情况下是做不到的,因为有时候会没有小数!例如:

> readHex "lol"
[]

所以要做好这个任务,你必须决定在意想不到的情况下你想要发生什么。在我看来,这就是帮助您思考需要编写哪些代码的类型系统。

您可以做出的一个选择是:如果文件的任何内容不是十六进制数字,则打印一条消息说明这一点并退出而不做任何其他事情。这是关于您可能得到的 coarsest-grained 回应;要完成这个任务,我们只需要记住到目前为止是否有错误。我们可以使用 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

其实把成功的案例放在第一位,其他的都放在return 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 变成一个延续,用 [=] 的列表做一些有趣的事情34=]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 -> {- ... -}