Personal tools

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, search


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