Preface
Goal: Progressive Tax Rate Formula in Haskell
I found a good income taxes case to be written in Haskell. Yes it is the progressive tax tariff formula in functional programming.
Following regulation in my country the tarrifs is defined as below:
Progressively
0 until 50 million: 5%
> 50 until 250 million: 15%
> 250 until 500 million: 25%
> 500 million : 30%
Cumulative equation in math can be described as below:
Spreadsheet Version
I have wrote an article in my local language, about making progressive tax tariff formula in spreadsheet:
Challenge
I found that the Excel function is very nice. So short that it only takes this one line:
=max( ({5;15;25;30}%*$PPh) - {0;5;30;55}*10^6 )
Can I do this shorter in Haskell ?
Short answer: No!
But I found that Haskell can solve this issue very nicely.
Meanwhile
It is after midnight here, so tired after attending a night class in campus. But I have promise myself to finish this article.
Simple Example
Calculation
With simple calculation using math the tarrif is as below:
50 million: 2.5 million
250 million: 32.5 million
500 million: 95 million
1000 million: 245 million
All in Rupiah currency.
Matplotlib Chart
With matplotlib we can plot above equation to this chart below:
Actually, this chart above is not very helpful. In order to have better understanding, we need infographic below.
Infographic Chart
Haskell Code
Typecast
Consider start writing code, with very simple typecast from Real to Integer.
-- taxable income
pkp :: Float
pkp = 1000000000
main = do
print $ round pkp
This will show
1000000000
You can use either Float
type.
If you need better precision, you may consider Double
type.
Using Function
Be lazy. Learn Haskell!
The next step is write down what I did in paper step by step, in function. Since Haskell is lazy and pure functional, the order of the function does not matter.
-- taxable income
pkp :: Double
pkp = 1000000000
-- income tax using progressive tariff
(t1, t2, t3) = (50000000, 250000000, 500000000)
pph :: Double -> Double
pph pkp = if pkp <= t1
then pph_t1 pkp
else pph_t2 pkp
pph_t1 :: Double -> Double
pph_t1 pkp = pkp * 0.05
pph_t2 :: Double -> Double
pph_t2 pkp = if pkp <= t2
then (pkp - t1) * 0.15 + pph_t1(t1)
else pph_t3 pkp
pph_t3 :: Double -> Double
pph_t3 pkp = if pkp <= t3
then (pkp - t2) * 0.25 + pph_t2(t2)
else pph_t4 pkp
pph_t4 :: Double -> Double
pph_t4 pkp = (pkp - t3) * 0.30 + pph_t3(t3)
main = do
print $ round $ pph pkp
Code above will result as below
245000000
Actually the code above does not looks good. We can rephrase the sentence above to better code poetry.
Using Guard and Recursive Function
Guard combined with Recursive Function, can resolve the function very nicely.
-- taxable income
pkp :: Double
pkp = 1000000000
-- income tax using progressive tariff
pph :: Double -> Double
pph pkp = pkpr pkp
where
(t1, t2, t3) = (50000000, 250000000, 500000000)
pkpr pkp
| pkp <= t1 = pkp * 0.05
| pkp <= t2 = (pkp - t1) * 0.15 + pph t1
| pkp <= t3 = (pkp - t2) * 0.25 + pph t2
| otherwise = (pkp - t3) * 0.30 + pph t3
main = do
print $ round (pph pkp)
When we no longer use recursive controlled by pkp <= t1
.
Otherwise, we will have endlees loop.
Guard can control the tail of of recursive.
Now our last issue, calculated value in my country should be in integer, rather than real number.
Integer Value
How do we round it inside function?
We should typecast the taxable income in the first place.
-- taxable income
pkp :: Int
pkp = 10^9
-- income tax using progressive tariff
pph :: Int -> Int
pph pkp = round $ pph_recursive $ fromIntegral pkp
where
[t1, t2, t3] = map (* 10^6) [50, 250, 500]
pph_recursive pkp_real = pkp_guard pkp_real
pkp_guard pkp
| pkp <= t1 = pkp * 0.05
| pkp <= t2 = (pkp - t1) * 0.15 + pph_rec t1
| pkp <= t3 = (pkp - t2) * 0.25 + pph_rec t2
| otherwise = (pkp - t3) * 0.30 + pph_rec t3
main = print $ pph pkp
Notice that we are no longer need to use round in main do
clause.
And we can even omit do
in oneliner fashioned.
The code is very nice and intuitive.
What is Next ?
How about the challenge above ?
There are other way to do this calculation. Consider continue reading [ Haskell - Tax Tariff - Part Two ].
Thank you for visiting.