packages feed

tax 0.2.0.0 → 0.2.1.0

raw patch · 2 files changed

+116/−66 lines, 2 filesdep −semigroupsdep ~basePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: semigroups

Dependency ranges changed: base

API changes (from Hackage documentation)

+ Data.Tax: infixr 6 <>
- Data.Tax: Tax :: a -> b -> Tax a b
+ Data.Tax: Tax :: (a -> b) -> Tax a b
- Data.Tax: class Profunctor (p :: * -> * -> *)
+ Data.Tax: class Profunctor (p :: Type -> Type -> Type)
- Data.Tax: dimap :: Profunctor p => a -> b -> c -> d -> p b c -> p a d
+ Data.Tax: dimap :: Profunctor p => (a -> b) -> (c -> d) -> p b c -> p a d
- Data.Tax: effective :: (Fractional a) => Money a -> Tax (Money a) (Money a) -> Tax (Money a) (Money a)
+ Data.Tax: effective :: Fractional a => Money a -> Tax (Money a) (Money a) -> Tax (Money a) (Money a)
- Data.Tax: flat :: (Num a) => a -> Tax (Money a) (Money a)
+ Data.Tax: flat :: Num a => a -> Tax (Money a) (Money a)
- Data.Tax: greaterOf :: (Ord a) => Tax b a -> Tax b a -> Tax b a
+ Data.Tax: greaterOf :: Ord a => Tax b a -> Tax b a -> Tax b a
- Data.Tax: lesserOf :: (Ord a) => Tax b a -> Tax b a -> Tax b a
+ Data.Tax: lesserOf :: Ord a => Tax b a -> Tax b a -> Tax b a
- Data.Tax: limit :: (Ord a) => a -> Tax b a -> Tax b a
+ Data.Tax: limit :: Ord a => a -> Tax b a -> Tax b a
- Data.Tax: lmap :: Profunctor p => a -> b -> p b c -> p a c
+ Data.Tax: lmap :: Profunctor p => (a -> b) -> p b c -> p a c
- Data.Tax: marginal :: (Fractional a, Ord a) => [(Money a, a)] -> Tax (Money a) (Money a)
+ Data.Tax: marginal :: (Num a, Ord a) => [(Money a, a)] -> Tax (Money a) (Money a)
- Data.Tax: rmap :: Profunctor p => b -> c -> p a b -> p a c
+ Data.Tax: rmap :: Profunctor p => (b -> c) -> p a b -> p a c
- Data.Tax: thresholds :: (Fractional a, Ord a) => [(Money a, a)] -> Tax (Money a) (Money a)
+ Data.Tax: thresholds :: (Num a, Ord a) => [(Money a, a)] -> Tax (Money a) (Money a)
- Data.Tax: type MoneyTax a = Tax (Money a) (Money a)
+ Data.Tax: type MoneyTax a = Tax Money a Money a

Files

src/Data/Tax.hs view
@@ -14,12 +14,50 @@ -- You should have received a copy of the GNU Affero General Public License -- along with this program.  If not, see <http://www.gnu.org/licenses/>. +{-# LANGUAGE GeneralizedNewtypeDeriving #-}+ {-|  This library provides combinators for constructing taxes.  It is based on the <https://hackage.haskell.org/package/dollaridoos dollaridoos> library. +-}+module Data.Tax+  (+  -- * Overview+  -- $doc++  -- * API+    Tax(..)+  , MoneyTax+  , lump+  , flat+  , threshold+  , threshold'+  , thresholds+  , above+  , above'+  , marginal+  , lesserOf+  , greaterOf+  , limit+  , effective++  -- * Re-exports+  , module Data.Money+  , Semigroup(..)+  , Monoid(..)+  , Profunctor(..)+  ) where++import Data.Profunctor (Profunctor(..))+import Data.Semigroup (Semigroup(..))++import Data.Money++{- $doc+ The most basic tax is a flat rate tax:  @@@ -29,31 +67,41 @@ To compute the tax, use 'getTax':  @-λ> 'getTax' businessTax (review money 1000000)+λ> 'getTax' businessTax (Money 1000000) $300000.0 @  Taxes form a semigroup (sum of tax outputs) and monoid:  @-λ> getTax (flat 0.1 <> flat 0.2) (review money 10)+λ> getTax (flat 0.1 <> flat 0.2) (Money 10) $3.0-λ> getTax mempty (review money 10)+λ> getTax mempty (Money 10) $0 @ -Marginal tax rates can be constructed using the 'above' combinator,+Progressive taxes can be constructed using the 'above' combinator, which taxes the amount above a given threshold at a flat rate.  @ individualIncomeTax =-  'above' (review money 18200) 0.19-  <> 'above' (review money 37000) (0.325 - 0.19)-  <> 'above' (review money 87000) (0.37 - 0.325)-  <> 'above' (review money 180000) (0.45 - 0.37)+     'above' (Money 18200 ) (0.19  - 0     )+  <> 'above' (Money 45000 ) (0.325 - 0.19  )+  <> 'above' (Money 120000) (0.37  - 0.325 )+  <> 'above' (Money 180000) (0.45 - 0.37   ) @ -Taxes can be negative.  For exmaple, the 'lump', 'above' and 'limit'+The 'marginal' function provides a shorthand for the above.++@+individualIncomeTax = 'marginal'+  [ ( Money 18200,  0.19  - 0     )+  , ( Money 45000,  0.325 - 0.19  )+  , ( Money 120000, 0.37  - 0.325 )+  , ( Money 180000, 0.45  - 0.37  ) ]+@++Taxes can be negative.  For example, the 'lump', 'above' and 'limit' combinators can be used to construct a low-income tax offset that starts at $445 and reduces at a rate of 1.5c per dollar earned over $37000:@@ -61,21 +109,28 @@ @ lowIncomeTaxOffset =   'limit' mempty-  ('lump' (review money (-445)) <> 'above' (review money 37000) 0.015)+  ('lump' (Money (-445)) <> 'above' (Money 37000) 0.015) @  The 'threshold' combinator applies a tax to the full input amount,-if it exceeds the threshold.  Some taxes have "shade-in" where the-amount above the threshold is taxed at a higher rate to "catch up"-to some lower flat rate.  The 'threshold'' and 'lesserOf'-combinators can be used to construct this tax:+if it exceeds the threshold.  @-medicareLevy =-  'threshold'' l ('lesserOf' ('above' l 0.1) ('flat' 0.02))-    where l = review money 21656+medicareLevySurcharge =+     'threshold' (review money 90000 ) 0.0100+  <> 'threshold' (review money 105000) 0.0025+  <> 'threshold' (review money 140000) 0.0025 @ +Some taxes have "shade-in" where the amount above some threshold is+taxed at a higher rate to "catch up" to some lower flat rate.  The+'above' and 'lesserOf' combinators can be used to construct this+tax:++@+medicareLevy l = 'lesserOf' ('above' l 0.1) ('flat' 0.02)+@+ Although some of the combinators deal directory with 'Money', a 'Tax' can be defined for other types.  For example, you can tax a person a certain number of days labour, based on their age.@@ -95,40 +150,8 @@  -} -{-# LANGUAGE GeneralizedNewtypeDeriving #-}--module Data.Tax-  (-  -- * Constructing taxes-    Tax(..)-  , MoneyTax-  , lump-  , flat-  , threshold-  , threshold'-  , thresholds-  , above-  , above'-  , marginal-  , lesserOf-  , greaterOf-  , limit-  , effective--  -- * Miscellanea-  , Semigroup(..)-  , Monoid(..)-  , Profunctor(..)-  , module Data.Money-  ) where--import Data.Monoid (Monoid(..))-import Data.Profunctor (Profunctor(..))-import Data.Semigroup (Semigroup(..))--import Data.Money---- | A function from gross income to tax payable.+-- | A function from an amount or value subject to taxation, to+-- the amount or value of tax due. -- -- Taxes form a semigroup where the tax payable is the -- sum of tax payable of consituent taxes.@@ -154,15 +177,15 @@ above' :: (Num b, Ord b) => Money b -> Tax (Money b) a -> Tax (Money b) a above' l = lmap (\x -> max (x $-$ l) mempty) --- | Convert a @[(threshold, rate)]@ into a marginal tax.+-- | Convert a @[(threshold, rate)]@ into a progressive tax. -- The rates are /cumulative/, i.e. the top marginal rate is the -- sum of the rates that apply for a given input. ---marginal :: (Fractional a, Ord a) => [(Money a, a)] -> Tax (Money a) (Money a)+marginal :: (Num a, Ord a) => [(Money a, a)] -> Tax (Money a) (Money a) marginal = foldMap (uncurry above)  --- | A lump-sum tax; a fixed value, not affected by the size of the input+-- | A lump-sum tax; a fixed value (ignores input). -- lump :: a -> Tax b a lump = Tax . const@@ -186,10 +209,10 @@ -- extra 10% at 50000: -- -- @--- tax = thresholds [(30000, .2), (50000, .1)]+-- tax = thresholds [(30000, 0.2), (50000, 0.1)] -- @ ---thresholds :: (Fractional a, Ord a) => [(Money a, a)] -> Tax (Money a) (Money a)+thresholds :: (Num a, Ord a) => [(Money a, a)] -> Tax (Money a) (Money a) thresholds = foldMap (uncurry threshold)  -- | Levy the lesser of two taxes@@ -202,8 +225,8 @@  -- | Limit the tax payable to the given amount ----- This could be used e.g. for limiting a compulsory loan--- repayment to the balance of the loan, or ensuring a+-- This could be used e.g. to limit a compulsory loan+-- repayment to the balance of the loan, or ensure a -- (negative) tax offset does not become a (positive) tax. -- limit :: (Ord a) => a -> Tax b a -> Tax b a
tax.cabal view
@@ -1,19 +1,19 @@+cabal-version:       2.2 name:                tax-version:             0.2.0.0+version:             0.2.1.0 synopsis:            Types and combinators for taxes description:   This library provides combinators for constructing taxes.  It is based on   the <https://hackage.haskell.org/package/dollaridoos dollaridoos> library.-license:             AGPL-3+license:             AGPL-3.0-or-later license-file:        LICENSE author:              Fraser Tweedale maintainer:          frase@frase.id.au copyright:           Copyright (C) 2018 Fraser Tweedale category:            Finance build-type:          Simple-cabal-version:       >=1.10 tested-with:-  GHC==7.10.3, GHC==8.0.2, GHC==8.2.1, GHC==8.4.3+  GHC ==8.10.7 || ==9.0.2 || ==9.2.8 || ==9.4.8 || ==9.6.7 || ==9.8.4 || ==9.10.2 || ==9.12.2  homepage:            https://github.com/frasertweedale/hs-tax bug-reports:         https://github.com/frasertweedale/hs-tax/issues@@ -21,16 +21,43 @@   type: git   location: https://github.com/frasertweedale/hs-tax.git +common common+  default-language: Haskell2010+  ghc-options:+    -Wall+    -Wcompat+    -Werror=missing-methods+    -Widentities+    -Wincomplete-record-updates+    -Wincomplete-uni-patterns+    -Wmissing-export-lists+    -Wnoncanonical-monad-instances+    -Wpartial-fields+    -Wredundant-constraints+    -Wunused-packages+    -fhide-source-paths+  if impl(ghc >= 9.0)+    ghc-options:+      -Winvalid-haddock+      -Werror=unicode-bidirectional-format-characters+  if impl(ghc >= 9.2)+    ghc-options:+      -Wimplicit-lift+      -Woperator-whitespace+      -Wredundant-bang-patterns+  if impl(ghc >= 9.4)+    ghc-options:+      -Wredundant-strictness-flags+  build-depends:+    base >= 4.14 && < 5+ library+  import: common   exposed-modules:     Data.Tax   -- other-modules:   -- other-extensions:   build-depends:-    base >= 4.8 && < 5     , dollaridoos >= 0.1     , profunctors >= 5.1-    , semigroups >= 0.16   hs-source-dirs:      src-  default-language:    Haskell2010-  ghc-options: -Wall