Alternative Calculation

Just like what I said in previous, we can rid of the guard.

Using List and Maximum

List come to the rescue.

-- taxable incomes
pkps :: [Int]
pkps = [50*10^6, 250*10^6, 500*10^6, 10^9]

-- income tax using progressive tariff
pph :: Int -> Int
pph pkp = maximum $ [round(x) | x <- pph_list]
    where
      -- Typecast, such as to Double
      pkp_d = fromIntegral(pkp)
      -- to avoid typo in writing digit
      million = 10^6
      -- tariff rate in percent
      pph_p = [0.05, 0.15, 0.25, 0.30]
      -- difference, short version
      pph_d = [0, 5, 30, 55]
      -- difference, in million rupiah
      pph_dj = map (fromIntegral <$> (*million)) pph_d
      -- range list, zero based index
      level   = [0, 1, 2, 3]
      -- main calculation, calulate all level
      pph_list = [pkp_d * (pph_p !! x) - (pph_dj !! x) | x <- level]

main = print $ map pph pkps

Code above will have the result as below

2500000
32500000
95000000
245000000

The downside of the method in code above is, all four ranges calculated first before finding the maximum value. It does not looks efficient.

Can the code be shorter ?

Dictionary

We can compress the list further into dictionary.

-- [(percentage, difference)]
tariffSchema :: [(Double, Int)]
tariffSchema =
    [(0.05,  0)
    ,(0.15,  5)
    ,(0.25, 30)
    ,(0.30, 55)
    ]

First and Second

And access the value using, fst (first) and snd (second) as below code

  [ fromIntegral pkp * fst(x) - snd(x) * (1000000)
  | x <- [(0.05, 0), (0.15, 5), (0.25, 30), (0.30, 55)]
  ]

Simply List

Or even simpler, just a list.

-- taxable incomes
pkps :: [Int]
pkps = [50*10^6, 250*10^6, 500*10^6, 10^9]

-- income tax using progressive tariff
pph :: Int -> Int
pph pkp = round $ maximum $  
  [ fromIntegral pkp * a - b * (10^6)
  | (a, b) <- [(0.05, 0), (0.15, 5), (0.25, 30), (0.30, 55)]
  ]

main = mapM_ (print . pph) pkps

Code above will also result some lines for as below

2500000
32500000
95000000
245000000

Haskell: Progressive Tax Tariff Code

The final code doesn’t feel as clear as our first post. And also it is not efficient as it has to calculate all four ranges.

List Comprehensions

The issue with maximum can be solved. With last I found the right range, and calculate only what I need.

import Data.Foldable

-- taxable incomes
pkps :: [Int]
pkps = [50*10^6, 250*10^6, 500*10^6, 10^9]

-- income tax using progressive tariff
pph :: Int -> Int
pph pkp = round $
    (\(t, p, d) -> fromIntegral pkp * p - d * (10^6))
    (reff !! last indices)
  where
    -- [(level, percentage, diff)]
    reff    = [(0, 0.05, 0), (50, 0.15, 5), (250, 0.25, 30), (500, 0.30, 55)]
    indices = [ i | (i, (t, p, d)) <- zip [0..] reff, pkp >= (t * 10^6) ]

main = forM_ pkps (print . pph)

Notice that I also import the Data.Foldable, so that we can have for loop like syntax.

import Data.Foldable

...

main = forM_ pkps (print . pph)

Code above will display the result line by line for each calculatin, as shown in below output:

2500000
32500000
95000000
245000000

This code looks so cryptic. And it also longer than the previous one.

I guess I fail miserably.


What is Next ?

What do you think, the coolest code, between this four article?

We can go back to original calculation code from the first article, and let’s see if we can make simplified the code. Consider continue reading [ Haskell - Tax Tariff - Part Four ].

Thank you for visiting.