Fraser Tweedale
March 17, 2023
66

# A tax combinator library could be useful for Rules-as-Code [lightning talk]

Lightning talk at Everything Open 2023.

I demonstrate the Haskell /tax/ library and introduce /tax-ato/,
a library for Australian personal income tax calculations.

March 17, 2023

## Transcript

1. A tax combinator library could be useful for
Rules as Code
or: surely you didn’t think you’d escape without hearing me talk about Haskell?
Fraser Tweedale
@[email protected]
March 16, 2023

2. Rates Rebate Act 1973 (NZ) s 3(1)
A ratepayer who, at the commencement of a rating year, was the
ratepayer of a residential property is entitled, on application
in that year, to a rebate of—
(a) so much of the rates payable for that rating year in respect of
the property as represents—
(i) two-thirds of the amount by which those rates exceed \$160,
reduced by—
(ii) \$1 for each \$8 by which the ratepayer’s income for the
preceding tax year exceeded \$28,080, that last-mentioned
amount being increased by \$500 in respect of each person who
was a dependant of the ratepayer at the commencement of the
rating year in respect of which the application is made; or
(b) \$700,—
whichever amount is smaller.

3. incomeThreshold :: Natural -> Money Rational
incomeThreshold numDependants =
Money (28080 + fromIntegral numDependants * 500)
reduction :: Natural -> Tax (Money Rational) (Money Rational)
reduction numDependants =
above (incomeThreshold numDependants ) ( -1/8)
rebate :: Natural -> Money Rational
-> Tax (Money Rational) (Money Rational)
rebate numDependants income =
lesserOf
( lump (Money 700))
( greaterOf
( lump (Money 0))
( above (Money 160) (2/3)
<> lump ( getTax (reduction numDependants ) income )))

4. Combinators:
functions that compose smaller computations into a more complex
computation. . .
that (typically) follow some laws. . .
such that our ability to reason about the computation can scale as it grows.

5. medicareLevy loThreshold =
lesserOf ( above loThreshold 0.1) ( flat 0.02)

6. lowIncomeTaxOffset =
limit (Money 0)
( lump (Money ( -445))
<> above (Money 37000) 0.015
)

7. individualIncomeTax = marginal’
[ ( 18200 , 0.19 )
, ( 45000 , 0.325 - 0.19 )
, (120000 , 0.37 - 0.325)
, (180000 , 0.45 - 0.37 ) ]

8. data Tax b a = Tax { getTax :: b -> a }
deriving ( Semigroup, Monoid, Functor, Profunctor )

9. allTheTaxes =
individualIncomeTax
<> medicareLevy (Money 23226)
<> lowIncomeTaxOffset
weeklyWithholding = dimap (\$* 52) (\$/ 52) allTheTaxes
fnlyWithholding = dimap (\$* 26) (\$/ 26) allTheTaxes
monthlyWithholding = dimap (\$* 12) (\$/ 12) allTheTaxes

https://github.com/frasertweedale/hs-tax
blog post: https://is.gd/tax_combinators
useful for "Rules as Code" calculations
relating to tax, levies, rates, rebates,
payroll...

11. What do /I/ use it for?
hs-tax-ato - personal income tax library
https://github.com/frasertweedale/hs-tax-ato

12. hs-tax-ato: stuﬀ that’s implemented
individual income tax, employee share schemes
Medicare levy, Medicare levy surcharge
HELP (HECS/SFSS student loans)
deductions
oﬀsets: low income, LMITO, spouse contribution
dividends, CGT, foreign income, foreign income tax oﬀset
rates/rules for previous ﬁnancial years (back to 2017)

13. hs-tax-ato: stuﬀ that’s NOT implemented
PAYG instalments (coming soon)
some adjustments/variations based on family income or dependents
partnership/trust/personal services income
super income streams and lump payments
some "grandfathering" rules (e.g. CGT indexation method)
lots of other esoteric (to me) features and quirks

14. hs-tax-ato: known issues
needs updates for 2022–23 FY (coming soon)
missing some rounding steps
lack of usage examples

15. Maybe these libraries will be useful or interesting to
someone...