Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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.

Slide 3

Slide 3 text

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 )))

Slide 4

Slide 4 text

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.

Slide 5

Slide 5 text

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

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

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

Slide 10

Slide 10 text

https://hackage.haskell.org/package/tax 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...

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

hs-tax-ato: stuff that’s implemented individual income tax, employee share schemes Medicare levy, Medicare levy surcharge HELP (HECS/SFSS student loans) deductions offsets: low income, LMITO, spouse contribution private health insurance rebate adjustments dividends, CGT, foreign income, foreign income tax offset rates/rules for previous financial years (back to 2017)

Slide 13

Slide 13 text

hs-tax-ato: stuff 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

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

© 2023 Fraser Tweedale Except where otherwise noted this work is licensed under http://creativecommons.org/licenses/by/4.0/ Code https://github.com/frasertweedale Blog frasertweedale.github.io/blog-fp Fediverse @[email protected]