-- This Haskell program converts positive integers to the English
-- phrase equivalent.

-- It only deals correctly with integers of up to 6 digits.

-- Adapted from Introduction to Functional Programming,
-- by Richard Bird & Philip Wadler.

-- The main function is convert.  Type "convert 13472" for example.

-- There is also a version `wordify' that prints the string to
-- standard output rather than returning the string as result.

-- Clem Baker-Finch, February 2006
------------------------------------------------------------------

convert2 :: Int -> String
convert2 n = combine2 (tens n)

tens :: Int -> (Int,Int)
tens n = (n `div` 10, n `mod` 10)

unitwords, teenwords, tenwords :: [String]
unitwords = ["zero","one","two","three","four","five","six","seven",
	     "eight","nine"]
teenwords = ["ten","eleven","twelve","thirteen","fourteen","fifteen",
             "sixteen","seventeen","eighteen","nineteen"]
tenwords  = ["twenty","thirty","forty","fifty","sixty","seventy",
             "eighty","ninety"]

combine2 :: (Int,Int) -> String
combine2 (0, u)   = unitwords!!u
combine2 (1, u)   = teenwords!!u
combine2 (t, 0)   = tenwords!!(t-2)	-- remember indexing is from 0
combine2 (t, u)   = tenwords!!(t-2) ++ "-" ++ unitwords!!u


convert3 :: Int -> String
convert3 n = combine3 (hundreds n)

hundreds :: Int -> (Int,Int)
hundreds n = (n `div` 100, n `mod` 100)

combine3 :: (Int,Int) -> String
combine3 (0, u)   = convert2 u
combine3 (h, 0)   = unitwords!!h ++ " hundred"
combine3 (h, u)   = unitwords!!h ++ " hundred and " ++ convert2 u


convert6 :: Int -> String
convert6 n = combine6 (thousands n)

thousands :: Int -> (Int,Int)
thousands n = ( n `div` 1000, n `mod` 1000)

combine6 :: (Int,Int) -> String
combine6 (0, u)  = convert3 u
combine6 (th, 0) = convert3 th ++ " thousand"
combine6 (th, u) = convert3 th ++ " thousand" ++ link u ++ convert3 u

link h 
     | h < 100    = " and "
     | otherwise  = ", "

-------------------------------
-- Add a full stop... why not?

convert :: Int -> String
convert n = convert6 n ++ "."

-------------------------------
-- Print the converted result to standard output.

wordify :: Int -> IO()
wordify n = putStrLn (convert n)

