liczby

Created: 2011-07-12 14:37
Updated: 2018-05-11 12:53

README.md

Liczby

Liczby (IPA: ˈlʲid͡ʐbɨ) is a tiny tool which converts decimal numerals to Polish words. It accepts a single number as the only command line argument and returns a string on its standard output. It's written in Haskell.

TL;DR? Get GHC and make && ./liczby 123456789.

We begin with importing the getArgs function, which will be necessary to read the argument passed to the main function.

module Main where
import System.Environment (getArgs)

As specified in the first paragraph, the algorithm takes an Integer and returns a String. The makeWords function calls an appropriate helper function depending on the magnitude of the input.

makeWords :: Integer -> String
makeWords x | x < 20 && x >= 0  = makeLessThenTwenty x
            | x < 100           = makeTens x
            | x < 1000          = makeHundreds x
            | x < 1000000       = makeThousands x
            | x < 1000000000    = makeMillions x
            | x < 1000000000000 = makeMilliards x

Values lesser than twenty are hardcoded.

makeLessThenTwenty x = case x of
  0 -> "zero"
  1 -> "jeden"
  2 -> "dwa"
  3 -> "trzy"
  4 -> "cztery"
  5 -> "pięć"
  6 -> "sześć"
  7 -> "siedem"
  8 -> "osiem"
  9 -> "dziewięć"
  10 -> "dziesięć"
  11 -> "jedenaście"
  12 -> "dwanaście"
  13 -> "trzynaście"
  14 -> "czternaście"
  15 -> "piętnaście"
  16 -> "szesnaście"
  17 -> "siedemnaście"
  18 -> "osiemnaście"
  19 -> "dziewiętnaście"

Numbers greater than 19 and lesser than 100 are divided into two parts: the number of hundreds concatenated with the rest of the input. The concatenation is performed by the prefixedWith function, which will be described shortly.

makeTens x = (x `mod` 10) `prefixedWith` case x' of
  2 -> "dwadzieścia"
  3 -> "trzydzieści"
  4 -> "czterdzieści"
  _ -> makeWords x' ++ "dziesiąt"
  where x' = x `div` 10

The conversion of remaining numbers lower than 1000 is analogous.

makeHundreds x = (x `mod` 100) `prefixedWith` case x' of
  1 -> "sto"
  2 -> "dwieście"
  3 -> "trzysta"
  4 -> "czterysta"
  _ -> makeWords x' ++ "set"
  where x' = x `div` 100

Now it's time for something more interesting. Numbers greater than 1000 may need both singular and plural forms. Quite funnily, in Polish there are two forms of plural. The rules are pretty simple.

data Plural = Singular | FirstPlural | SecondPlural

plural x | x == 1                        = Singular
         | x < 5                         = FirstPlural
         | x > 20 && x' `elem` [2, 3, 4] = FirstPlural
         | otherwise                     = SecondPlural
         where x' = x `mod` 10

Now we'll need a function which will use singular or plural appropriately. The makePlural function takes as its arguments the base number, its singular and plural forms and the number to be converted.

makePlural n singular firstPlural secondPlural x =
  (x `mod` n) `prefixedWith` pluralize (plural x')
    where x' = x `div` n
          prefix = makeWords x'
          pluralize Singular     = singular
          pluralize FirstPlural  = prefix ++ " " ++ firstPlural
          pluralize SecondPlural = prefix ++ " " ++ secondPlural

By using makePlural we can easily implement conversion functions for numbers greater than or equal to 1000.

makeThousands = makePlural 1000       "tysiąc"  "tysiące"  "tysięcy"
makeMillions  = makePlural 1000000    "milion"  "miliony"  "milionów"
makeMilliards = makePlural 1000000000 "miliard" "miliardy" "miliardów"

The last necessary function is prefixedWith. It takes a number and a prefix string and concatenates the prefix and the number if the number isn't equal to zero.

prefixedWith :: Integer -> String -> String
prefixedWith rest prefix = if rest /= 0
                            then prefix ++ " " ++ makeWords rest
                            else prefix

Finally, the main function reads the first argument given in the command line, converts it to an Integer, translates it to Polish and prints it.

main = do x:_ <- getArgs
          putStrLn $ makeWords (read x :: Integer)

Simple, isn't it?

© 2011 Jan Stępień. Feel free to use the code under terms of the MIT license.

Cookies help us deliver our services. By using our services, you agree to our use of cookies Learn more