Variable states and dynamic scope calls
Introduction
In this section, the tutorial picks up where the previous section left, that is to say implementing the computation of the household tax for one individual. Now, we still have to aggregate the computations for individuals at the household level to generate the whole household tax.
Doing this aggregation will require calling the scope HouseholdTaxInvidualComputation
multiple times for a list aggregation inside HouseholdTaxComputation
. We
will cover this topic, but first we have to wrap up unfinished business
from the last section of the tutorial!
Recap of the previous section
Recap of the previous section
This section of the tutorial builds up on the previous one, and will reuse the same running example, but all the Catala code necessary to execute the example is included below for reference.
```catala
declaration structure Individual:
data income content money
data number_of_children content integer
declaration scope IncomeTaxComputation:
input current_date content date
input individual content Individual
input overseas_territories content boolean
internal tax_rate content decimal
output income_tax content money
```
## Article 1
The income tax for an individual is defined as a fixed percentage of the
individual's income over a year.
```catala
scope IncomeTaxComputation:
definition income_tax equals
individual.income * tax_rate
```
## Article 2 (old version before 2000)
The fixed percentage mentioned at article 1 is equal to 20 %.
```catala
scope IncomeTaxComputation:
label article_2
definition tax_rate under condition
current_date < |2000-01-01|
consequence equals 20%
```
## Article 2 (new version after 2000)
The fixed percentage mentioned at article 1 is equal to 21 % %.
```catala
scope IncomeTaxComputation:
# Simply use the same label "article_2" as the previous definition to group
# them together
label article_2
definition tax_rate under condition
current_date >= |2000-01-01|
consequence equals 21%
```
## Article 3
If the individual is in charge of 2 or more children, then the fixed
percentage mentioned at article 1 is equal to 15 %.
```catala
scope IncomeTaxComputation:
label article_3 exception article_2
definition tax_rate under condition
individual.number_of_children >= 2
consequence equals 15%
```
## Article 4
Individuals earning less than $10,000 are exempted of the income tax mentioned
at article 1.
```catala
scope IncomeTaxComputation:
label article_4 exception article_3
definition tax_rate under condition
individual.income <= $10,000
consequence equals 0%
```
## Article 5
Individuals earning more than $100,000 are subjects to a tax rate of
30%, regardless of their number of children.
```catala
scope IncomeTaxComputation:
label article_5 exception article_3
definition tax_rate under condition
individual.income > $100,000
consequence equals 30%
```
## Article 6
In the overseas territories, the tax rate for individuals earning
more than $100,000 specified at article 5 is reduced to 25 %.
```catala
scope IncomeTaxComputation:
label article_6 exception article_5
definition tax_rate under condition
individual.income > $100,000 and overseas_territories
consequence equals 25%
```
## Article 7
When several individuals live together, they are collectively subject to
the household tax. The household tax owed is $10000 per individual of the household,
and half the amount per children.
```catala
declaration scope HouseholdTaxComputation:
input individuals content list of Individual
output household_tax content money
declaration scope HouseholdTaxIndividualComputation:
input individual content Individual
input overseas_territories content boolean
input current_date content date
income_tax_computation scope IncomeTaxComputation
output household_tax content money
```
```catala
# scope HouseholdTaxIndividualComputation:
# # This definition is disabled because of the new one in Article 8.
# definition household_tax equals
# $10000 * (1.0 + decimal of individual.number_of_children / 2.0)
# The definition of household tax for the whole household below is wrong and
# will be refactored in the next section.
scope HouseholdTaxComputation:
definition household_tax equals
let number_of_individuals equals number of individuals in
let number_of_children equals
sum integer
of individual.number_of_children for individual among individuals
in
$10,000
* (
decimal of number_of_individuals
+ decimal of number_of_children / 2.0
)
```
## Article 8
The amount of income tax paid by each individual can be deducted from the
share of household tax owed by this individual.
```catala
scope HouseholdTaxIndividualComputation:
definition income_tax_computation.individual equals
individual
definition income_tax_computation.overseas_territories equals
overseas_territories
definition income_tax_computation.current_date equals
current_date
definition household_tax equals
let tax equals
$10,000 * (1.0 + decimal of individual.number_of_children / 2.0)
in
let deduction equals income_tax_computation.income_tax in
# Don't forget to cap the deduction!
if deduction > tax then $0 else tax - deduction
```
## Test
```catala
declaration scope Test:
output computation content IncomeTaxComputation
scope Test:
definition computation equals
output of IncomeTaxComputation with {
-- individual:
Individual {
-- income: $20,000
-- number_of_children: 0
}
-- overseas_territories: false
-- current_date: |1999-01-01|
}
declaration scope TestHousehold:
output computation content HouseholdTaxComputation
scope TestHousehold:
definition computation equals
output of HouseholdTaxComputation with {
-- individuals:
[ Individual {
-- income: $15,000
-- number_of_children: 0
} ;
Individual {
-- income: $80,000
-- number_of_children: 2
} ]
}
declaration scope TestIndividualHousehold:
output computation content HouseholdTaxIndividualComputation
scope TestIndividualHousehold:
definition computation equals
output of HouseholdTaxIndividualComputation with {
-- individual:
Individual {
-- income: $15,000
-- number_of_children: 0
}
-- current_date: |1999-01-01|
-- overseas_territories: false
}
```
Variable states
Recall that we have defined household_tax
in a single sweep
inside HouseholdTaxIndividualComputation
:
scope HouseholdTaxIndividualComputation:
definition household_tax equals
let tax equals
$10,000 * (1.0 + decimal of individual.number_of_children / 2.0)
in
let deduction equals income_tax_computation.income_tax in
# Don't forget to cap the deduction!
if deduction > tax then $0 else tax - deduction
However, doing so merges together the specifications of article 7 and article 8,
which goes against the spirit of Catala to split the code in the same structure
as the legal text. So, instead of using two local variables inside the definition
of household_tax
, we want to split the formula into two distinct definition
.
Intuitively, this implies creating two scope variables in
HouseholdTaxIndividualComputation
, household_tax_base
(for article 7) and
household_tax_with_deduction
(article 8). But really, this amounts to giving
two consecutive states for the variable household_tax
, and lawyers understand
the code better this way! So Catala has a feature to let you exactly that:
declaration scope HouseholdTaxIndividualComputation:
input individual content Individual
input overseas_territories content boolean
input current_date content date
income_tax_computation scope IncomeTaxComputation
output household_tax content money
# The different states for variable "household_tax" are declared here,
# in the exact order in which you expect them to be computed!
state base
state with_deduction
With our two states base
and with_deduction
, we can code up articles 7 and
8:
Article 7
When several individuals live together, they are collectively subject to the household tax. The household tax owed is $10,000 per individual of the household, and half the amount per children.
scope HouseholdTaxIndividualComputation:
definition household_tax state base equals
$10,000 * (1.0 + decimal of individual.number_of_children / 2.0)
Article 8
The amount of income tax paid by each individual can be deducted from the share of household tax owed by this individual.
scope HouseholdTaxIndividualComputation:
definition household_tax state with_deduction equals
# Below, "household_tax" refers to the value of "household_tax" computed
# in the previous state, so here the state "base" which immediately precedes
# the state "with_deduction" in the declaration.
if income_tax_computation.income_tax > household_tax then $0
else
household_tax - income_tax_computation.income_tax
# It is also possible to refer to variable states explicitely with the
# syntax "household_tax state base".
Elsewhere in HouseholdTaxIndividualComputation
, using household_tax
will
implicitly refer to the last state of the variable (so here with_deduction
),
matching the usual implicit convention in legal texts.
This completes our implementation of HouseholdTaxIndividualComputation
! Its
output variable household_tax
now contains the share of household tax owed by
each individual of the household, with the correct income tax deduction.
We can now use it in the computation of the global household tax in
HouseholdTaxComputation
.
Linking scopes together through list mapping
We can now finish coding up article 7 by adding together each share of the
household tax owned by all the individuals of the household. We will do
that through list aggregation, as previously, but the elements of the list to
aggregate are now the result of calling HouseholdTaxIndividualComputation
on each individual. Previously, we have showed how to call a sub-scope
statically and exactly one time. But here, this is not what we want: we want
to call the sub-scope as many times as there are individuals in the household.
We then have to use a different method for calling the sub-scope:
With all our refactorings, the declaration of the scope HouseholdTaxComputation
can be simplified (we don't need the function variable share_household_tax
anymore):
declaration scope HouseholdTaxComputation:
input individuals content list of Individual
output household_tax content money
Then, the definition of household_tax
could be re-written as follows next
to article 7:
scope HouseholdTaxComputation:
definition household_tax equals
sum money
of (
(
# Below is the syntax for calling the sub-scope
# "HouseholdTaxIndividualComputation" dynamically, on the spot.
# after "with" is the list of inputs of the scope.
output of HouseholdTaxIndividualComputation with {
# The next three lines are tautological in this example, because
# the names of the parameters and the names of the scope variables
# are identical, but the values of the scope call parameters can be
# arbitrarily complex!
-- individual: individual # <- this last "invididual" is the map variable
-- overseas_territories: overseas_territories
-- current_date: current_date
}
# The construction "output of <X> with { ... }" returns a structure
# containing all the output variables of scope <X>. Hence, we access
# output variable "household_tax" of scope
# "HouseholdTaxIndividualComputation" with the field access syntax
# ".household_tax".
).household_tax
)
for individual among individuals
That's it! We've finished implementing article 7 and article 8 in a clean, extensible, future-proof fashion using a series of scopes that call each other.
Testing and debugging the computation
We have written quite complex code in this tutorial section, it is high time to test and debug it. Similarly to the test presented in the first tutorial section, we can declare a new test scope for the household tax computation, and execute it:
declaration scope TestHousehold:
output computation content HouseholdTaxComputation
scope TestHousehold:
definition computation equals
output of HouseholdTaxComputation with {
-- individuals:
[ Individual {
-- income: $15,000
-- number_of_children: 0
} ;
Individual {
-- income: $80,000
-- number_of_children: 2
} ]
-- overseas_territories: false
-- current_date: |1999-01-01|
}
catala interpret tutorial.catala_en --scope=TestHousehold
┌─[RESULT]─
│ computation = HouseholdTaxComputation { -- household_tax: $21,500.00 }
└─
Is the result of the test correct ? Let's see by unrolling the computation manually:
- The household tax for two individuals and two children is
2 * $10,000 + 2 * $5,000
, so $30,000; - The first individual earns more than $10,000, less than $100,000, has no children and we are before the year 2000, so the income tax rate is 20 % per article 2 and their income tax is $3,000;
- The share of household tax for the first individual is $10,000, so the deduction for the first individual is the full $3,000;
- The second individual earns more than $10,000, less than $100,000$, but has two children so the income tax rate is 15 % per article 3 and their income tax is $12,000;
- The share of household tax for the second individual is $20,000, so the deduction for the second individual is the full $12,000$;
- The total deduction is thus $15,000$, which is capped at $8,500 per article 9;
- Applying the deduction to the base household tax yields $21,500.
So far so good, the test result is correct. But it might have gotten to the
right result by taking the wrong intermediate steps, so we'll want to
inspect them. Fortunately, the Catala interpreter can print the full
computation trace for that purpose. Here is the output on the interpretation
of TestHousehold
:
Trace of TestHousehold
Trace of TestHousehold
$ catala interpret tutorial.catala_en --scope=TestHousehold --trace
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition computation equals
│ ‾‾‾‾‾‾‾‾‾‾‾
Test
[LOG] → HouseholdTaxComputation.direct
[LOG] ≔ HouseholdTaxComputation.direct.
input: HouseholdTaxComputation_in { -- individuals_in: [Individual { -- income: $15,000.00 -- number_of_children: 0 }; Individual { -- income: $80,000.00 -- number_of_children: 2 }] -- overseas_territories_in: false -- current_date_in: 1999-01-01 }
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition shares_of_household_tax equals
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 7
[LOG] → HouseholdTaxIndividualComputation.direct
[LOG] ≔ HouseholdTaxIndividualComputation.direct.
input: HouseholdTaxIndividualComputation_in { -- individual_in: Individual { -- income: $15,000.00 -- number_of_children: 0 } -- overseas_territories_in: false -- current_date_in: 1999-01-01 }
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition household_tax equals
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 7
[LOG] ≔ HouseholdTaxIndividualComputation.household_tax: $10,000.00
[LOG] → IncomeTaxComputation.direct
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition income_tax_computation.current_date equals
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 8
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition income_tax_computation.individual equals
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 8
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition income_tax_computation.overseas_territories equals
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 8
[LOG] ≔ IncomeTaxComputation.direct.
input: IncomeTaxComputation_in { -- current_date_in: 1999-01-01 -- individual_in: Individual { -- income: $15,000.00 -- number_of_children: 0 } -- overseas_territories_in: false }
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ current_date < |2000-01-01|
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 2 (old version before 2000)
[LOG] ≔ IncomeTaxComputation.tax_rate: 0.2
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition income_tax equals
│ ‾‾‾‾‾‾‾‾‾‾
Article 1
[LOG] ≔ IncomeTaxComputation.income_tax: $3,000.00
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ income_tax_computation scope IncomeTaxComputation
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 7
[LOG] ≔ IncomeTaxComputation.direct.
output: IncomeTaxComputation { -- income_tax: $3,000.00 }
[LOG] ← IncomeTaxComputation.direct
[LOG] ≔ HouseholdTaxIndividualComputation.
income_tax_computation: IncomeTaxComputation { -- income_tax: $3,000.00 }
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition deduction equals
│ ‾‾‾‾‾‾‾‾‾
Article 8
[LOG] ≔ HouseholdTaxIndividualComputation.deduction: $3,000.00
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ output of HouseholdTaxIndividualComputation with {
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ -- individual: individual
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ -- overseas_territories: overseas_territories
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ -- current_date: current_date
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ }
│ ‾
Article 7
[LOG] ≔ HouseholdTaxIndividualComputation.direct.
output: HouseholdTaxIndividualComputation { -- household_tax: $10,000.00 -- deduction: $3,000.00 }
[LOG] ← HouseholdTaxIndividualComputation.direct
[LOG] → HouseholdTaxIndividualComputation.direct
[LOG] ≔ HouseholdTaxIndividualComputation.direct.
input: HouseholdTaxIndividualComputation_in { -- individual_in: Individual { -- income: $80,000.00 -- number_of_children: 2 } -- overseas_territories_in: false -- current_date_in: 1999-01-01 }
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition household_tax equals
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 7
[LOG] ≔ HouseholdTaxIndividualComputation.household_tax: $20,000.00
[LOG] → IncomeTaxComputation.direct
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition income_tax_computation.current_date equals
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 8
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition income_tax_computation.individual equals
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 8
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition income_tax_computation.overseas_territories equals
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 8
[LOG] ≔ IncomeTaxComputation.direct.
input: IncomeTaxComputation_in { -- current_date_in: 1999-01-01 -- individual_in: Individual { -- income: $80,000.00 -- number_of_children: 2 } -- overseas_territories_in: false }
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ individual.number_of_children >= 2
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 3
[LOG] ≔ IncomeTaxComputation.tax_rate: 0.15
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition income_tax equals
│ ‾‾‾‾‾‾‾‾‾‾
Article 1
[LOG] ≔ IncomeTaxComputation.income_tax: $12,000.00
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ income_tax_computation scope IncomeTaxComputation
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 7
[LOG] ≔ IncomeTaxComputation.direct.
output: IncomeTaxComputation { -- income_tax: $12,000.00 }
[LOG] ← IncomeTaxComputation.direct
[LOG] ≔ HouseholdTaxIndividualComputation.
income_tax_computation: IncomeTaxComputation { -- income_tax: $12,000.00 }
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition deduction equals
│ ‾‾‾‾‾‾‾‾‾
Article 8
[LOG] ≔ HouseholdTaxIndividualComputation.deduction: $12,000.00
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ output of HouseholdTaxIndividualComputation with {
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ -- individual: individual
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ -- overseas_territories: overseas_territories
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ -- current_date: current_date
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ }
│ ‾
Article 7
[LOG] ≔ HouseholdTaxIndividualComputation.direct.
output: HouseholdTaxIndividualComputation { -- household_tax: $20,000.00 -- deduction: $12,000.00 }
[LOG] ← HouseholdTaxIndividualComputation.direct
[LOG] ≔ HouseholdTaxComputation.
shares_of_household_tax: [HouseholdTaxIndividualComputation { -- household_tax: $10,000.00 -- deduction: $3,000.00 }; HouseholdTaxIndividualComputation { -- household_tax: $20,000.00 -- deduction: $12,000.00 }]
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition household_tax
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 7
[LOG] ≔ HouseholdTaxComputation.household_tax#base: $30,000.00
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition total_deduction
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 8
[LOG] ≔ HouseholdTaxComputation.total_deduction#base: $15,000.00
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition total_deduction
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 9
[LOG] ≔ HouseholdTaxComputation.total_deduction#capped: $8,500.00
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ definition household_tax
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾
Article 8
[LOG] ≔ HouseholdTaxComputation.household_tax#deduction: $21,500.00
[LOG] ☛ Definition applied:
─➤ tutorial.catala_en
│
│ output of HouseholdTaxComputation with {
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ -- individuals:
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ [ Individual {
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ -- income: $15,000
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ -- number_of_children: 0
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ } ;
│ ‾‾‾
│ Individual {
│ ‾‾‾‾‾‾‾‾‾‾‾‾
│ -- income: $80,000
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ -- number_of_children: 2
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ } ]
│ ‾‾‾
│ -- overseas_territories: false
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ -- current_date: |1999-01-01|
│ ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
│ }
│ ‾
Test
[LOG] ≔ HouseholdTaxComputation.direct.
output: HouseholdTaxComputation { -- household_tax: $21,500.00 }
[LOG] ← HouseholdTaxComputation.direct
[LOG] ≔ TestHousehold.computation: HouseholdTaxComputation { -- household_tax: $21,500.00 }
Inspecting the trace reveals the structure of the computation that matches closely the legal reasonning we did just above to compute the test output manually. With this powerful tool, it is possible to debug and maintain Catala programs at scale.
Conclusion
Congratulations for finishing the Catala tutorial! The last two sections have not presented features that are unique to Catala, unlike the exceptions from the second section. Rather, in Catala we use the classic software engineering techniques from functional programming to split the code into multiple functions that call each other at the right level of abstraction, with the goal to keep the code close where it is specified in the law. There are various ways to express something in Catala, but the proximity between the code and the legal specification should be the proxy for what is the idiomatic way to do things.
Refactoring the Catala code continuously as new legal requirements are added or updated is the key to maintaining the codebase efficiently over the long term, and avoiding the spaghetti code that is common when translating law to code. We hope this tutorial put you on the right track for your journey into Catala and the wonderful world of safely and faithfully automating legal provisions.
We encourage you to read the next chapters of this book to continue learning how to use Catala, as the tutorial is not set in a real-world software development projet setup, and misses a lot of tips about coding in Catala but also interacting with lawyers.
Recap of the current section
Recap of the current section
For reference, here is the final version of the Catala code consolidated at the end of this section of the tutorial.
```catala
declaration structure Individual:
data income content money
data number_of_children content integer
declaration scope IncomeTaxComputation:
input current_date content date
input individual content Individual
input overseas_territories content boolean
internal tax_rate content decimal
output income_tax content money
```
## Article 1
The income tax for an individual is defined as a fixed percentage of the
individual's income over a year.
```catala
scope IncomeTaxComputation:
definition income_tax equals
individual.income * tax_rate
```
## Article 2 (old version before 2000)
The fixed percentage mentioned at article 1 is equal to 20 %.
```catala
scope IncomeTaxComputation:
label article_2
definition tax_rate under condition
current_date < |2000-01-01|
consequence equals 20%
```
## Article 2 (new version after 2000)
The fixed percentage mentioned at article 1 is equal to 21 % %.
```catala
scope IncomeTaxComputation:
# Simply use the same label "article_2" as the previous definition to group
# them together
label article_2
definition tax_rate under condition
current_date >= |2000-01-01|
consequence equals 21%
```
## Article 3
If the individual is in charge of 2 or more children, then the fixed
percentage mentioned at article 1 is equal to 15 %.
```catala
scope IncomeTaxComputation:
label article_3 exception article_2
definition tax_rate under condition
individual.number_of_children >= 2
consequence equals 15%
```
## Article 4
Individuals earning less than $10,000 are exempted of the income tax mentioned
at article 1.
```catala
scope IncomeTaxComputation:
label article_4 exception article_3
definition tax_rate under condition
individual.income <= $10,000
consequence equals 0%
```
## Article 5
Individuals earning more than $100,000 are subjects to a tax rate of
30%, regardless of their number of children.
```catala
scope IncomeTaxComputation:
label article_5 exception article_3
definition tax_rate under condition
individual.income > $100,000
consequence equals 30%
```
## Article 6
In the overseas territories, the tax rate for individuals earning
more than $100,000 specified at article 5 is reduced to 25 %.
```catala
scope IncomeTaxComputation:
label article_6 exception article_5
definition tax_rate under condition
individual.income > $100,000 and overseas_territories
consequence equals 25%
```
## Article 7
When several individuals live together, they are collectively subject to
the household tax. The household tax owed is $10000 per individual of the household,
and half the amount per children.
```catala
declaration scope HouseholdTaxComputation:
input individuals content list of Individual
input overseas_territories content boolean
input current_date content date
internal shares_of_household_tax
content list of HouseholdTaxIndividualComputation
internal total_deduction content money
state base
state capped
output household_tax content money
state base
state deduction
declaration scope HouseholdTaxIndividualComputation:
input individual content Individual
input overseas_territories content boolean
input current_date content date
income_tax_computation scope IncomeTaxComputation
output household_tax content money
output deduction content money
```
```catala
scope HouseholdTaxIndividualComputation:
definition household_tax equals
$10000 * (1.0 + decimal of individual.number_of_children / 2.0)
scope HouseholdTaxComputation:
definition shares_of_household_tax equals
(
output of HouseholdTaxIndividualComputation with {
-- individual: individual
-- overseas_territories: overseas_territories
-- current_date: current_date
}
)
for individual among individuals
definition household_tax
state base
equals
sum money
of share_of_household_tax.household_tax
for share_of_household_tax among shares_of_household_tax
```
## Article 8
The amount of income tax paid by each individual can be deducted from the
share of household tax owed by this individual.
```catala
scope HouseholdTaxIndividualComputation:
definition income_tax_computation.individual equals
individual
definition income_tax_computation.overseas_territories equals
overseas_territories
definition income_tax_computation.current_date equals
current_date
definition deduction equals
if income_tax_computation.income_tax > household_tax then household_tax
else
income_tax_computation.income_tax
scope HouseholdTaxComputation:
definition total_deduction
state base
equals
sum money
of share_of_household_tax.deduction
for share_of_household_tax among shares_of_household_tax
definition household_tax
state deduction
equals
if total_deduction > household_tax then $0
else household_tax - total_deduction
```
## Article 9
The deduction granted at article 8 is capped at $8,500 for the whole household.
```catala
scope HouseholdTaxComputation:
definition total_deduction
state capped
equals
if total_deduction > $8,500 then $8,500 else total_deduction
```
## Test
```catala
declaration scope Test:
output computation content IncomeTaxComputation
scope Test:
definition computation equals
output of IncomeTaxComputation with {
-- individual:
Individual {
-- income: $20,000
-- number_of_children: 0
}
-- overseas_territories: false
-- current_date: |1999-01-01|
}
declaration scope TestHousehold:
output computation content HouseholdTaxComputation
scope TestHousehold:
definition computation equals
output of HouseholdTaxComputation with {
-- individuals:
[ Individual {
-- income: $15,000
-- number_of_children: 0
} ;
Individual {
-- income: $80,000
-- number_of_children: 2
} ]
-- overseas_territories: false
-- current_date: |1999-01-01|
}
```