16

Is there a library function to put commas into numbers with Haskell?

I want a function that would work something like this:

format 1000000 = "1,000,000"
format 1045.31 = "1,045.31"

but I can't seem to find any number formatting functions of this type in Haskell. Where are the number formatting functions?

Chris Stryczynski
  • 30,145
  • 48
  • 175
  • 286
Nate
  • 161
  • 1
  • 3

6 Answers6

10

Perhaps you could use some of the functions from Data.Split:

http://hackage.haskell.org/cgi-bin/hackage-scripts/package/split

I know this isn't quite what you want, but you could use Data.List.intersperse

http://haskell.org/ghc/docs/6.12.1/html/libraries/base-4.2.0.0/Data-List.html#v:intersperse

EDIT: This does what you want, although I know you want a library function, this may be as close as you get (please excuse my poor coding style):

import Data.List.Split
import Data.List

format x = h++t
    where
        sp = break (== '.') $ show x
        h = reverse (intercalate "," $ splitEvery 3 $ reverse $ fst sp) 
        t = snd sp
Jonno_FTW
  • 8,601
  • 7
  • 58
  • 90
2

Using the format-numbers library

Prelude> import Data.Text.Format.Numbers
Prelude Data.Text.Format.Numbers> prettyF (PrettyCfg 2 (Just ',') '.') 2132871293.3412
"2,132,871,293.34"
Chris Stryczynski
  • 30,145
  • 48
  • 175
  • 286
1

(from hier: http://bluebones.net/2007/02/formatting-decimals-in-haskell/)

Formatting Decimals in Haskell

A formatting function to go from numbers like 333999333.33 to “333,999,999.33″ in Haskell. Copes with negative numbers and rounds to 2 dp (easy to add a paramater for that should you wish).

Examples:

*Main> formatDecimal 44

"44.00"

*Main> formatDecimal 94280943.4324

"94,280,943.43"

*Main> formatDecimal (-89438.329)

"-89,438.33"

import Data.Graph.Inductive.Query.Monad (mapFst)
import List
import Text.Printf

formatDecimal d
    | d < 0.0   = "-" ++ (formatPositiveDecimal (-d))
    | otherwise = formatPositiveDecimal d
    where formatPositiveDecimal = uncurry (++) . mapFst addCommas . span (/= '.') . printf "%0.2f"
          addCommas = reverse . concat . intersperse "," . unfoldr splitIntoBlocksOfThree . reverse
          splitIntoBlocksOfThree l = case splitAt 3 l of ([], _) -> Nothing; p-> Just p
Jogusa
  • 5,530
  • 5
  • 24
  • 23
  • Nice handling of negatives. If you don't happen to have the fgl package installed, the base package includes `first` from Control.Arrow that can replace `mapFst`. (Recent version of base have Data.Bifunctor, which defines a `first` that is usable in the same way.) – rob Jun 21 '20 at 22:06
0

I've had this problem myself. My very pragmatic solution (using Text as T) is this:

T.replace (T.singleton '.') (T.singleton ',') $
T.pack $
showFixed False 42.0

Does not work for separators, though. That was fine with me.

For me Locale is not helpful unless there is a way to set it.

LennyStackOverflow
  • 2,228
  • 1
  • 19
  • 22
0

Another solution that I'm using:

thousands :: Double -> Text
thousands d = T.intercalate "." $ case T.splitOn "." (T.pack (show d)) of
    x:xs -> (T.pack . reverse . go . reverse . T.unpack) x : xs
    xs -> xs
  where
    go (x:y:z:[])    = x:y:z:[]
    go (x:y:z:['-']) = x:y:z:['-']
    go (x:y:z:xs)    = x:y:z:',':go xs
    go xs            = xs
John Wiegley
  • 6,972
  • 1
  • 16
  • 20
-2

Check out the Text.Printf module in base:

https://hackage.haskell.org/package/base-4.9.0.0/docs/Text-Printf.html

Chris Martin
  • 30,334
  • 10
  • 78
  • 137
Raghs
  • 33
  • 1
  • 4
    I'm not sure this works for what is requested. This simply provides `printf`, but what implementation of `printf` supports regional numeric display with commas? What he wants is something like [Number::Format](http://search.cpan.org/dist/Number-Format/Format.pm) for perl. – Evan Carroll Sep 20 '10 at 15:54