我正在学习haskell,目前正在尝试从字符串中解析Integers和Floats。
然而,当我在“342”或任何没有单个或多个非数字字符的“数字”上尝试我的readNum函数时,ghci向我报告:
* 异常:parse.hs:125:18-46:模式的无可辩驳模式失败(i,(a :as))
data Token
= IntTok Int | FloatTok Float | EOF
readNum :: String->(Token, String)
readNum [] = (EOF, [])
readNum xs = let (i, (a:as)) = span isDigit xs --This is line 125
in (case a of
('.') -> let (j, (b:c:bs)) = span isDigit as
in (if ((toLower b) == 'e' && (c == '+' || c == '-' || (isDigit c)))
then (let (k, d) = span isDigit bs in (FloatTok (read (concat [i,[a],j, [b],[c],k])::Float), d))
else (FloatTok (read (concat [i,[a],j])::Float), (b:c:bs)))
_ -> (IntTok (read i::Int), (a:as)))
当span isDigit xs
返回空列表作为元组的第二个元素时,是否有更好的方法来处理这种情况?
-Thanks
答案 0 :(得分:6)
您收到错误是因为如果您使用"342"
之类的简单整数,那么span isDigit "342"
只是("342",[])
,而(l,a:as)
无法匹配。应该始终匹配的模式称为无可辩驳模式。正如您所发现的那样,let绑定中的模式是无可辩驳的,所以......
您需要坚持在let绑定中始终匹配的模式。例如,你可以做
readNum xs = let (i, ps) = span isDigit xs
in (case ps of
('.':as) -> let (j, qs) = span isDigit as in case qs of
b:c:bs -> if ..........
_ -> error "not enough stuff after decimal number"
_ -> ....
我给出了一个愚蠢的错误信息,但很明显你应该在那里写出更明智的代码。