Haskell Quiz/English Numerals/Solution Michael Sloan

From HaskellWiki
< Haskell Quiz‎ | English Numerals
Revision as of 20:47, 14 December 2009 by Newacct (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.


Probably not as elegant as it could be, but handles a huge number of... numbers. More than any of the ruby programs, I'm sure. Feel free to edit it for elegance.

prefixes =                ["", "un", "duo","tre","quattuor","quin",   "sex", "septen","octo", "novem"]
suffixes = ["dec"]++(map (++"gint") ["vi", "tri","quadra",  "quinqua","sexa","septua","octo", "nona"])

aname 0 = ""
aname 1 = "thousand"
aname 101 = "centillion"
aname n | n > 101 = error "Can't name american numbers over with more than 303 decimal digits"
aname n = (if n <= 10 then    ["m",  "b",  "tr", "quadr",   "quint",  "sext","sept",  "oct",  "non"] !! (n-2)
                     else (prefixes !! ((n-1) `mod` 10)) ++ (suffixes !! ((n-1) `div` 10 - 1))
         ) ++ "illion"

ename 0 = ""
ename 1 = "thousand"
ename 200 = "centillion"
ename 201 = "centilliard"
ename n | n > 201 = error "Can't name european numbers over with more than 603 decimal digits"
ename n = (if n < 20 then    ["m",  "b",  "tr", "quadr",   "quint",  "sext","sept",  "oct",  "non"] !! ((n `div` 2)-1)
                     else (prefixes !! ((n `div` 2) `mod` 10)) ++ (suffixes !! (n `div` 20 - 1))
         ) ++ "illi" ++ (if even n then "on" else "ard")

digits = ["zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine"]

triple :: Integer -> Int -> (Int -> String) -> String
triple 0 _ _ = ""
triple n i f | n > 999 = triple (n `div` 1000) (i+1) f ++ (if n `mod` 1000 /= 0 then ", " ++ triple (n `mod` 1000) i f else "")
triple n 0 _ | n > 99 && (n `mod` 100) == 0 = digits !! (fromIntegral $ n `div` 100) ++ " hundred"
triple n 0 f | n > 99 = triple (n `div` 100 * 100) 0 f ++ " and " ++ triple (n `mod` 100) 0 f
triple n 0 _ | n `mod` 10 == 0 = ["", "ten", "twenty", "thirty", "fourty", "fifty", "sixty", "seventy", "eighty", "ninety"] !! (fromIntegral $ n `div` 10)
triple n 0 _ | n > 10 && n < 20 = ["eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"] !! (fromIntegral $ n - 11)
triple n 0 _ | n < 10 = digits !! (fromIntegral n)
triple n 0 f = triple (n `div` 10 * 10) 0 f ++ " " ++ triple (n `mod` 10) 0 f
triple n i f | n <= 999 = triple n 0 f ++ " " ++ f i

americanNumber 0 = "zero"
americanNumber x = triple x 0 aname

europeanNumber 0 = "zero"
europeanNumber x = triple x 0 ename