[Haskell-cafe] parsing currency amounts with parsec

Antoine Latter aslatter at gmail.com
Tue May 10 04:04:25 CEST 2011


On Mon, May 9, 2011 at 5:07 PM, Eric Rasmussen <ericrasmussen at gmail.com> wrote:
> Hi everyone,
>
> I am relatively new to Haskell and Parsec, and I couldn't find any articles
> on parsing numbers in the following format:
>
> Positive: $115.33
> Negative: ($1,323.42)
>
> I'm working on the parser for practical purposes (to convert a 3rd-party
> generated, most unhelpful format into one I can use), and I'd really
> appreciate any insight into a better way to do this, or if there are any
> built-in functions/established libraries that would be better suited to the
> task. My code below works, but doesn't seem terribly efficient.
>

Why do you think it inefficient? Is it slow?

I don't have any substantial suggestions, but from a style perspective:

* I would question the use of IEEE binary-floating-point number types
for currency. Haskell ships with a fixed-point decimal library, but I
don't know how fast it is:
http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Fixed.html

* You can re-use the 'positive' parser in the 'negative' one:

> negAmount = do char '('
>               a <- posAmount
>               char ')'
>              return (negate a)

* In the 'currencyAmount' declaration, I'm not sure that you need the
'try' before the 'negAmount', but I don't know what the rest of your
grammar looks like.

> Thanks!
> Eric
>
> -------------------------------------------------
> {- parses positive and negative dollar amounts -}
>
> integer :: CharParser st Integer
> integer = PT.integer lexer
>
> float :: CharParser st Double
> float = PT.float lexer
>
> currencyAmount = try negAmount <|> posAmount
>
> negAmount = do char '('
>               char '$'
>               a <- currency
>               char ')'
>               return (negate a)
>
> posAmount = do char '$'
>               a <- currency
>               return a
>
> currency = do parts <- many floatOrSep
>              let result = combine orderedParts where
>                    combine = sumWithFactor 1
>                    orderedParts = reverse parts
>              return result
>
> floatOrSep = try float <|> beforeSep
>
> beforeSep = do a <- integer
>               char ','
>               return (fromIntegral a :: Double)
>
> sumWithFactor n []     = 0
> sumWithFactor n (x:xs) = n * x + next
>                         where next = sumWithFactor (n*1000) xs
>
>
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
>



More information about the Haskell-Cafe mailing list