# Number to word form

wordify:
Converts any integer number (such as 123456000999) into a string ("one billion two hundred ninety-three million one hundred two thousand one hundred").

``````module Wordify (wordifyWords, wordify) where

digiteenNames       :: [String]
digiteenNames       = ["", "one", "two", "three", "four", "five"
,"six", "seven", "eight", "nine", "ten"
,"eleven", "twelve", "thirteen", "fourteen"
,"fifteen","sixteen", "seventeen"
,"eighteen", "nineteen"
]

-- Returns the string form of a particular digit.
digiteen            :: Integer -> String
digiteen n          = digiteenNames !! fromIntegral n

tenNames            :: [String]
tenNames            = ["","","twenty", "thirty", "forty", "fifty"
,"sixty", "seventy", "eighty", "ninety"
]

-- Returns the string form for a particular multiple of ten.
tenName             :: Integer -> String
tenName n           = tenNames !! fromIntegral n

-- Converts a two digit number to its string form.
twodigit            :: Integer -> String
twodigit n | n < 20        = digiteen n
| units == 0    = tenName tens
| otherwise     = tenName tens ++ "-" ++ digiteen units
where (tens, units) = divMod n 10

-- Converts a three digit number to an array of words.  For example:
--
--   threedigit 54  = ["fifty-four"]
--   threedigit 923 = ["nine", "hundred", "twenty-three"]
--   threedigit 400 = ["four", "hundred"]

threedigit          :: Integer -> [String]
threedigit n
| hundi == 0    = [twodigit n]
| twodi == 0    = [digiteen hundi, "hundred"]
| otherwise     = [digiteen hundi, "hundred", twodigit twodi]
where (hundi, twodi) = divMod n 100

-- periodNames = [[], ["thousand"], ["million"], ...
--
-- This list uses fake names after decillion.
periodNames         :: [[String]]
periodNames         = [] : map (:[]) ps
where ps = ["thousand", "million", "billion", "trillion"
,"octillion", "septillion", "novemtillion"
,"decillion"] ++ fakes 11
fakes n = (wordify n ++ "-tillion") : fakes (n + 1)

-- Converts a large (or small) positive number to a list of words.
manydigit           :: Integer -> [String]
manydigit m         = aux periodNames m []
where aux _      0 tail = tail
aux (p:ps) n tail
= let (n', front) = divMod n 1000
in aux ps n' (case front of
0 -> tail
_ -> threedigit front ++ p ++ tail)

-- Converts any integer to word form, making a list of words.
wordifyWords        :: Integer -> [String]
wordifyWords n
| n < 0         = "negative" : manydigit (negate n)
| n == 0        = ["zero"] -- a special case!
| otherwise     = manydigit n

-- Converts an integer to string form.  For example,
-- wordify 123456000999 = "one hundred twenty-three billion \
--                        \four hundred fifty-six million \
--                        \nine hundred ninety-nine"
wordify             :: Integer -> String
wordify             = unwords . wordifyWords``````
Rashakil Fol 978

To evaluate the function, run ghci, load the file Wordify.hs with `:l Wordify` , and type `wordify 123456000999` at the prompt (or some other argument).

Lardmeister 461

Why does Haskell give such huge executable files? I compiled a simple "Hello world!" program using 'ghc --make hello.hs' and came up with an 'hello.exe' file of over 700 kb!

Rashakil Fol 978

I don't know. Because there's a bit of work and code that has to be executed for the garbage collector and other systems, I guess.

gwern

Lardmeister: a couple reasons. First, every GHC executable comes with the RTS, runtime system. This handles garbage collection, threading (or lack there of), profiling, and so on. There's actually quite a few options for it. This RTS eats up a couple hundred KB.
Second, the executables are statically linked - there is no libh along the lines of libc. Dynamic/shared libraries are coming; I'm not sure when, but I heard the GHC devs got it working on some non-Linux platform already, so my guess would be 6.10.
And third, I believe GHC by default leaves all the debugging symbols and whatnot in. Running strip might reclaim some space.

Finally, I'd like to note that binary size isn't so terrible since a lot of the code size is a fixed cost as I mentioned - it looks worst for a hello world. My customized XMonad, when stripped, is about 2.4 megabytes, while your hello world example would lead one to suspect a size considerably worse... Also, come on, this is an old and uninteresting topic. Does it bother you when you run a Python or Java or Common Lisp app that the interpreter is like 20-60 megs?

v6ak 0

It is great. However, there is probably a mistake: There slould be:

``| otherwise     = [digiteen hundi, "hundred and", twodigit twodi]``

``| otherwise     = [digiteen hundi, "hundred", twodigit twodi]``