【问题标题】:Haskell *** Exception: Prelude.read: no parseHaskell *** 例外:Prelude.read:没有解析
【发布时间】:2017-01-18 11:06:14
【问题描述】:
【问题讨论】:
标签:
parsing
haskell
parse-error
【解决方案1】:
read 是一个类型为read :: Read a => String -> a 的函数。这意味着read 将String 作为输入并返回某个类型a 的值,前提是a 实现Read 类型类。 read 必须知道要返回什么特定类型,并且它可以通过以下两种方式之一知道:要么明确地给它类型(例如 read "123" :: Int 或 read "True" :: Bool),要么它从上下文中推断出它。在您的情况下,read 推断它必须返回 Int,因为 LogMessage 期望 Int 作为其第二个参数。所以在这种情况下,表达式read [y] 的意思是:获取Char y,将其转换为单元素字符串,然后尝试通过解析将其转换为Int。现在,如果y 恰好包含一个不是十进制数字的字符,它将失败(通过抛出异常),因为它不知道如何将其转换为整数。
现在你该如何处理这个问题?在调用它之前,您必须检查read 的输入是否正常。例如,您可以检查y 是否为数字(使用appropriate function):
parseMessage (x:y:z)
| x == 'I' && isDigit y = LogMessage Info (read [y]) (unwords [z])
...
或者,您可以使用Text.Read 中的readMaybe,就像read,但它不会在失败时抛出异常,而是返回空值:
parseMessage (x:y:z)
| x == 'I', Just n <- readMaybe [y] = LogMessage Info n (unwords [z])
【解决方案2】:
问题是您的输入消息格式。您正在读取一行作为字符串,然后匹配字符串中的字符(因为字符串是[Char] 的类型别名)。
在您的sample.log 中,第一行 (I 6 Completed armadillo processing) 将作为字符串传递给parseMessage,参数将采用以下值:
x = 'I'
y = ' ' --single white space character
z = "6 Completed armadillo processing"
read 获取空白字符并抛出 *** Exception: Prelude.read: no parse
为了获取值,您可以执行以下操作:
parseMessage :: String -> LogMessage
parseMessage msg =
case words msg of
"I":y:z -> LogMessage Info (read y :: TimeStamp) (unwords z)
"W":y:z -> undefined
"E":y:z -> undefined
_ -> undefined
这样可以轻松提取前两个有效单词(本例中为MessageType 和TimeStamp)。