不可辩驳的模式在Let语句内部失败



我正在学习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返回一个空列表作为元组的第二个元素时,有更好的方法来处理这种情况吗?

-感谢

您会得到错误,因为如果您使用像"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"
                     _ -> .... 

我给出了一个愚蠢的错误信息,但很明显,您应该在那里编写更明智的代码。

最新更新