Haskell 中的异常处理没有解析

时间:2021-03-12 10:00:33

标签: haskell

所以我有一个文件,其中第一行的格式为 ([String], [(Int, Int)], [(Int, Int)], Int),其余行的格式为 [((Int, Int), (Int, Int), String)]。我设法获取输入并使用以下函数解析它:

someFunction :: String -> IO (String)
someFunction fileName = do
    handle <- openFile fileName ReadMode
    contents <- hGetLine handle
    let firstLine = read contents :: ([String], [(Int, Int)], [(Int, Int)], Int)
    restOfLines <- map read <$> lines <$> hGetContents handle :: IO [((Int, Int), (Int, Int), String)]
    ...

问题是,如果文件格式错误,我想打印自定义错误。因此,如果缺少某些东西或缺少某些东西,它应该只打印“一些错误”。否则,必须解析这些行,以便我可以对内容做一些其他的事情。如果有人能帮我解决这个问题,我将不胜感激。

1 个答案:

答案 0 :(得分:0)

检测 Read 解析器是否失败的最简单方法是使用 readMaybe。例如。在 GHCi 中:

> import Text.Read (readMaybe)

> :t readMaybe
readMaybe :: Read a => String -> Maybe a    -- Defined in ‘Text.Read’

> readMaybe "1" :: Maybe Int
Just 1

> readMaybe ":(" :: Maybe Int
Nothing

您可以使用 readMaybecase 的结果进行模式匹配,就像 Maybe 的任何其他用法一样:

case readMaybe input of
  Just parsed -> …  -- Use parsed value
  Nothing -> …      -- Report error

这只能报告一般性的失败;对于更复杂的解析和验证,您应该使用适当的解析库。 base 中包含的一个是 Text.ParserCombinators.ReadP:

import Control.Applicative (some)
import Data.Char (isDigit)
import Text.ParserCombinators.ReadP (ReadP)
import qualified Text.ParserCombinators.ReadP as ReadP

-- Parse one or more digits.
number :: ReadP Int
number = read <$> some (ReadP.satisfy isDigit)

这些解析器可以使用 readP_to_S 对某些输入执行;默认情况下,它们会枚举所有可能的解析,您可以使用 eof(需要完整输入)或 <++(有偏见的选择)等函数对其进行约束。

> import Text.ParserCombinators.ReadP (readP_to_S)

> readP_to_S number "123"
[(1,"23"),(12,"3"),(123,"")]

> readP_to_S (number <* ReadP.eof) "123"
[(123,"")]

您可以对结果列表进行模式匹配以验证,例如,只有一个结果并提取您想要的内容或报告错误。另一个流行的解析库选择是 megaparsec 包,它可以额外提供带有源位置的漂亮的自定义错误消息。