Skip to content

Instantly share code, notes, and snippets.

@pjrt
Last active March 1, 2019 21:24
Show Gist options
  • Save pjrt/469934cdcbbf3d4f471e4bb3709beb75 to your computer and use it in GitHub Desktop.
Save pjrt/469934cdcbbf3d4f471e4bb3709beb75 to your computer and use it in GitHub Desktop.
import Data.List (intersperse, foldl')
import Data.List.Split (chunksOf)
numbers :: Int -> String
numbers c =
case c of
0 -> ""
1 -> "one"
2 -> "two"
3 -> "three"
4 -> "four"
5 -> "five"
6 -> "six"
7 -> "seven"
8 -> "eight"
9 -> "nine"
otherwise -> error "Unexpected char"
teens :: Int -> String
teens c =
case c of
0 -> "ten"
1 -> "eleven"
2 -> "twelve"
3 -> "thirteen"
4 -> "fourteen"
5 -> "fifteen"
6 -> "sixteen"
7 -> "seventeen"
8 -> "eighteen"
9 -> "nineteen"
otherwise -> error "Unexpected char"
tens :: Int -> String
tens c =
case c of
2 -> "twenty"
3 -> "thirty"
4 -> "forty"
5 -> "fifty"
6 -> "sixty"
7 -> "seventy"
8 -> "eighty"
9 -> "ninety"
otherwise -> error "Unexpected char"
hundred :: Int -> String
hundred 0 = ""
hundred n = numbers n ++ " hundred"
over20 :: Int -> Int -> String
over20 x y = tens x ++ numbers y
-- Given a number zzzyyyxx, convert it into [[x,x], [y,y,y], [z,z,z]]
splitNumReverse :: (Num a, Show a) => a -> [[Int]]
splitNumReverse = map (map read . chunksOf 1) . chunksOf 3 . reverse . show
nameHundred :: [Int] -> String
nameHundred [x] = numbers x
nameHundred [1, y] = teens y
nameHundred [x, y] = over20 x y
nameHundred [x, 1, z] = hundred x ++ " and " ++ teens z
nameHundred [x, y, z] = hundred x ++ " and " ++ over20 y z
nameHundred o = error $ "Invalid section: " ++ show o
nameThousand :: Int -> Maybe String
nameThousand n =
case n of
4 -> Just "billion"
3 -> Just "million"
2 -> Just "thousand"
_ -> Nothing
-- Names of thousandth position. The order matters!
namesOfThousand :: [String]
namesOfThousand = ["", "thousand", "million", "billion"]
-- Given two lists, join them via their heads.
-- For example: 123 456 -> 142536. Stops at the spot where the first list ends
joinOnHeads :: [a] -> [a] -> [a]
joinOnHeads [] ys = []
joinOnHeads xs [] = []
joinOnHeads (x:xs) (y:ys) = [x, y] ++ joinOnHeads xs ys
-- Given a number, convert it into its English form, up to a billion
numberName :: (Num a, Show a) => a -> String
numberName n =
let splitted = splitNumReverse n
namedSections = map nameHundred splitted
in concat $ intersperse " " $ reverse $ joinOnHeads namesOfThousand namedSections
main :: IO ()
main = do
let testNum = 2340
putStrLn $ show $ reverse $ chunksOf 3 $ reverse $ show testNum
putStrLn $ numberName testNum
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment