Haskell Quiz/English Numerals/Solution Michael Sloan

From HaskellWiki
< Haskell Quiz‎ | English Numerals
Revision as of 10:47, 13 January 2007 by Quale (talk | contribs) (sharpen cat)
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.

[[Category:Haskell Quiz solutions|English Numerals]

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 n `mod` 2 == 0 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