import Data.List (intercalate, unfoldr)

spellInteger :: Integer -> String
spellInteger n
 | n <    0  = "negative " ++ spellInteger (-n)
 | n <   20  = small n
 | n <  100  = let (a, b) = n `divMod` 10
               in  tens a ++ nonzero '-' b
 | n < 1000  = let (a, b) = n `divMod` 100
               in  small a ++ " hundred" ++ nonzero ' ' b
 | otherwise = intercalate ", " $ map big $ reverse $
               filter ((/= 0) . snd) $ zip [0..] $ unfoldr uff n

 where nonzero :: Char -> Integer -> String
       nonzero _ 0 = ""
       nonzero c n = c: spellInteger n

       uff :: Integer -> Maybe (Integer, Integer)
       uff 0 = Nothing
       uff n = Just $ uncurry (flip (,)) $ n `divMod` 1000

       small, tens :: Integer -> String
       small = (["zero", "one", "two", "three", "four", "five",
            "six", "seven", "eight", "nine", "ten", "eleven",
            "twelve", "thirteen", "fourteen", "fifteen", "sixteen",
            "seventeen", "eighteen", "nineteen"] !!) . fromEnum
       tens = ([undefined, undefined, "twenty", "thirty", "forty",
           "fifty", "sixty", "seventy", "eighty", "ninety"] !!) .
           fromEnum

       big :: (Int, Integer) -> String
       big (0, n) = spellInteger n
       big (1, n) = spellInteger n ++ " thousand"
       big (e, n) = spellInteger n ++ ' ': (l !! e) ++ "illion"
         where l = [undefined, undefined, "m", "b", "tr", "quadr",
                   "quint", "sext", "sept", "oct", "non", "dec"]