Search code examples
haskellparsec

Parsing floating point numbers with Parsec of Haskell


There is some code used to run parsing over calculator inputs (both integer and floating ones):

import Text.Parsec hiding(digit)
import Data.Functor

type Parser a = Parsec String () a

digit :: Parser Char
digit = oneOf ['0'..'9']

fp_char :: Parser Char
fp_char = oneOf ['.', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9']

number :: Parser Integer 
number = read <$> many1 digit

fp_number :: Parser Double
fp_number = read <$> many1 fp_char

addition :: Parser Integer
addition = do
    lhv <- number
    spaces
    char '+'
    spaces
    rhv <- number
    return $ lhv + rhv

fp_addition :: Parser Double
fp_addition = do
    lhv <- fp_number
    spaces
    char '+'
    spaces
    rhv <- fp_number
    return $ lhv + rhv

Obviously, this will throw an exception once a float number input which preceded or followed by '.' without any digit before/after dot character respectively. How can I constrain string evaluation to prevent from execution failure?


Solution

  • fp_number  :: Parsec String () Double
    fp_number  = read <$> parser  where 
       parser = (++) <$> number <*> (option "" $ (:) <$> char '.'  <*> number )
    

    A side note, don't forget to handle negative numbers too.

    type Parser a = Parsec String () a
    
    digit :: Parser Char
    digit = -- same 
    
    number :: Parser String 
    number =  many1 digit
    
    fp_number  :: Parser  Double
    fp_number  = read <$> parser  where 
       parser = (++) <$> number <*> (option "" $ (:) <$> char '.'  <*> number )
    
    fp_addition :: Parser Double
    fp_addition = --same
    
    test = parseTest fp_addition "2.123 + 213.12"