Skip to content

Instantly share code, notes, and snippets.

@alexd1971
Created June 28, 2019 19:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexd1971/70be34c101f65cbcec6b990ffe32f311 to your computer and use it in GitHub Desktop.
Save alexd1971/70be34c101f65cbcec6b990ffe32f311 to your computer and use it in GitHub Desktop.
-- Грамматический род числительных
data Gender = Male | Female | Neuter deriving (Eq, Show)
-- Называет одну цифру (числа перого десятка)
sayDigits :: Gender -> Int -> String
sayDigits g x
| x == 1 && g == Male = "один"
| x == 1 && g == Female = "одна"
| x == 1 && g == Neuter = "одно"
| x == 2 && g == Female = "две"
| x == 2 = "два"
| x == 3 = "три"
| x == 4 = "четыре"
| x == 5 = "пять"
| x == 6 = "шесть"
| x == 7 = "семь"
| x == 8 = "восемь"
| x == 9 = "девять"
| otherwise = ""
-- Называет числа второго десятка
sayTeens :: Int -> String
sayTeens x
| x == 0 = "десять"
| x == 1 = "одиннадцать"
| x == 2 = "двенадцать"
| x == 3 = "тринадцать"
| x == 4 = "четырнадцать"
| x == 5 = "пятнадцать"
| x == 6 = "шестнадцать"
| x == 7 = "семнадцать"
| x == 8 = "восемнадцать"
| x == 9 = "девятнадцать"
| otherwise = ""
-- Называет десятки
sayTens :: Int -> String
sayTens x
| x == 2 = "двадцать"
| x == 3 = "тридцать"
| x == 4 = "сорок"
| x == 5 = "пятьдесят"
| x == 6 = "шестьдесят"
| x == 7 = "семьдесят"
| x == 8 = "восемьдесят"
| x == 9 = "девяносто"
| otherwise = ""
-- Называет сотни
sayHundreds :: Int -> String
sayHundreds x
| x == 1 = "сто"
| x == 2 = "двести"
| x == 3 = "триста"
| x == 4 = "четыреста"
| x == 5 = "пятьсот"
| x == 6 = "шестьсот"
| x == 7 = "семьсот"
| x == 8 = "восемьсот"
| x == 9 = "девятьсот"
| otherwise = ""
-- Называет трехзначное число (класс единиц)
sayOnes :: Gender -> (Int, Int, Int) -> String
sayOnes g (hundreds, tens, ones)
| tens == 1 = unwords [sayHundreds hundreds, sayTeens ones]
| otherwise = unwords [sayHundreds hundreds, sayTens tens, sayDigits g ones]
-- Называет класс тысяч
sayThousands :: (Int, Int, Int) -> String
sayThousands (0, 0, 0) = ""
sayThousands x
| tens == 1 = unwords [say x, "тысяч"]
| ones == 1 = unwords [say x, "тысяча"]
| ones > 1 && ones < 5 = unwords [say x, "тысячи"]
| otherwise = unwords [say x, "тысяч"]
where
say = sayOnes Female
(_, tens, ones) = x
-- Называет класс миллионов
sayMillions :: (Int, Int, Int) -> String
sayMillions (0, 0, 0) = ""
sayMillions x
| tens == 1 = unwords [say x, "миллионов"]
| ones == 1 = unwords [say x, "миллион"]
| ones > 1 && ones < 5 = unwords [say x, "миллиона"]
| otherwise = unwords [say x, "миллионов"]
where
say = sayOnes Male
(_, tens, ones) = x
-- Называет класс миллиардов
sayBillions :: (Int, Int, Int) -> String
sayBillions (0, 0, 0) = ""
sayBillions x
| tens == 1 = unwords [say x, "миллиардов"]
| ones == 1 = unwords [say x, "миллиард"]
| ones > 1 && ones < 5 = unwords [say x, "миллиарда"]
| otherwise = unwords [say x, "миллиардов"]
where
say = sayOnes Male
(_, tens, ones) = x
-- Разбивает число на цифры
splitByDigit :: Int -> [Int]
splitByDigit 0 = []
splitByDigit x = splitByDigit (div x 10) ++ [mod x 10]
-- Формирует класс числа из трёх цифр
classFromList :: [Int] -> (Int, Int, Int)
classFromList [] = (0, 0, 0)
classFromList [c] = (0, 0, c)
classFromList [b,c] = (0, b, c)
classFromList [a,b,c] = (a, b, c)
classFromList _ = error "Error converting List to Class"
-- Разбивает число на классы
splitByClasses :: Int -> [(Int, Int, Int)]
splitByClasses 0 = []
splitByClasses x = splitByClasses (div x 1000) ++ [(classFromList.splitByDigit) (mod x 1000)]
-- Называет число разбитое на классы
sayParsedNumber :: Gender -> [(Int, Int, Int)] -> String
sayParsedNumber g (x:xs)
| length xs == 3 = unwords (sayBillions x : [sayParsedNumber g xs])
| length xs == 2 = unwords (sayMillions x : [sayParsedNumber g xs])
| length xs == 1 = unwords (sayThousands x : [sayParsedNumber g xs])
| null xs = sayOnes g x
| otherwise = ""
-- Удаляет лишние пробелы из строки
removeRedundantSpaces :: String -> String
removeRedundantSpaces [] = ""
removeRedundantSpaces (x:xs)
| null xs = [x]
| otherwise =
if x == ' ' && head xs == ' '
then removeRedundantSpaces xs
else x:removeRedundantSpaces xs
-- Называет число
sayNumber :: Gender -> Int -> String
sayNumber _ 0 = "ноль"
sayNumber g x = (removeRedundantSpaces.sayParsedNumber g.splitByClasses) x
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment