Вопрос

I'm learning haskell and am currently trying to parse Integers and Floats from strings.

However, when trying my readNum function on "342" or any "number" that doesn't have a single or more non-numeric characters ghci reports to me:

* Exception: parse.hs:125:18-46: Irrefutable pattern failed for pattern (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)))

Is there a better way to handle the case when span isDigit xs returns an empty list as the second element of the tuple?

-Thanks

Это было полезно?

Решение

You're getting the error because if you use a simple Integer like "342" then span isDigit "342" is just ("342",[]), which can't match (l,a:as). A pattern that is supposed to always match is called an irrefutable pattern. As you've found out, patterns in let bindings are irrefutable, so...

You need to to stick to patterns that will always match in a let binding. For example you could do

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"
                     _ -> .... 

I gave a silly error message, but clearly you should write more sensible code there.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top