From 7292303c6a5e2b9764d1f3030ecbe67e90c498ae Mon Sep 17 00:00:00 2001 From: Denis Merigoux Date: Thu, 30 Jan 2025 16:08:40 +0100 Subject: [PATCH] Fini tutoriel --- examples/tutorial_end_2_3.catala_en | 94 ++++-- src/2-3-list-modular.md | 493 +++++++++++++++++++++++++++- 2 files changed, 557 insertions(+), 30 deletions(-) diff --git a/examples/tutorial_end_2_3.catala_en b/examples/tutorial_end_2_3.catala_en index 46368b9..1f1e889 100644 --- a/examples/tutorial_end_2_3.catala_en +++ b/examples/tutorial_end_2_3.catala_en @@ -112,7 +112,15 @@ declaration scope HouseholdTaxComputation: 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 @@ -122,33 +130,34 @@ declaration scope HouseholdTaxIndividualComputation: income_tax_computation scope IncomeTaxComputation output household_tax content money - state base - state with_deduction + output deduction content money ``` ```catala scope HouseholdTaxIndividualComputation: - definition household_tax - state base - equals - $1000 * (1.0 + decimal of individual.number_of_children / 2.0) + definition household_tax equals + $10000 * (1.0 + decimal of individual.number_of_children / 2.0) scope HouseholdTaxComputation: - definition household_tax equals - sum money - of ( - ( - output of HouseholdTaxIndividualComputation with { - -- individual: individual - -- overseas_territories: overseas_territories - -- current_date: current_date - } - ).household_tax + 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 +## Article 8 The amount of income tax paid by each individual can be deducted from the share of household tax owed by this individual. @@ -162,12 +171,36 @@ scope HouseholdTaxIndividualComputation: 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 with_deduction + state deduction equals - if income_tax_computation.income_tax > household_tax then $0 - else - household_tax - income_tax_computation.income_tax + 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 @@ -187,4 +220,23 @@ scope Test: -- 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| + } ``` diff --git a/src/2-3-list-modular.md b/src/2-3-list-modular.md index 578ba4c..2181644 100644 --- a/src/2-3-list-modular.md +++ b/src/2-3-list-modular.md @@ -6,6 +6,12 @@ applying to each element of the list. Here, Catala reuses all the common tricks and patterns from functional programming to elegantly structure the code while performing expressive operations on lists. +This section of the tutorial is quite challenging and involves some complexity +in the example. This complexity is necessary to illustrate how the features +of Catala scale to real-world legal texts that involve complex features. We +encourage the reader to persevere in their study of this section, and to +ask any question on the [online Catala community chat](https://zulip.catala-lang.org). + ~~~~~~admonish info collapsible=true title="Recap of the previous section" This section of the tutorial builds up on the [previous one](./2-2-conditionals-exceptions.md), and will reuse the same running example, but all the Catala code necessary @@ -27,7 +33,7 @@ sum, with a reduced rate for the children: ~~~admonish quote title="Article 7" When several individuals live together, they are collectively subject to -the household tax. The household tax owed is $1000 per individual of the household, +the household tax. The household tax owed is $10,000 per individual of the household, and half the amount per children. ~~~ @@ -83,7 +89,9 @@ x + 2 ~~~ For step 1, we simply need to get the lenght of the list `individuals`, which -can be done through the syntax `number of individuals`[^note]. For step 2, we +can be done through the syntax `number of individuals` (the syntax for all list +operations can be found in [the syntax sheat cheet](https://catalalang.github.io/catala/syntax.pdf) +or in the [language reference](./5-catala.md)). For step 2, we need to aggregate the number of children for all individuals, which can be done through the syntax `sum integer of individual.number_of_children for individual among individuals`. Notice the type indication (`integer`) for the `sum`, which @@ -100,7 +108,7 @@ scope HouseholdTaxComputation: sum integer of individual.number_of_children for individual among individuals in - $1000 + $10,000 * ( # "number_of_individuals" is an integer, but money can only be multiplied # by decimals: we need to explicitly cast before using the value @@ -352,13 +360,13 @@ With our two states `base` and `with_deduction`, we can code up articles 7 and #### Article 7 When several individuals live together, they are collectively subject to -the household tax. The household tax owed is $1000 per individual of the household, +the household tax. The household tax owed is $10,000 per individual of the household, and half the amount per children. ```catala scope HouseholdTaxIndividualComputation: definition household_tax state base equals - $1000 * (1.0 + decimal of individual.number_of_children / 2.0) + $10,000 * (1.0 + decimal of individual.number_of_children / 2.0) ``` #### Article 8 @@ -421,17 +429,484 @@ scope HouseholdTaxComputation: 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 { - -- individual: individual + # 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 with { ... }" returns a structure + # containing all the output variables of scope . Hence, we access + # output variable "household_tax" of scope + # "HouseholdTaxIndividualComputation" with the field access syntax + # ".household_tax". ).household_tax ) for individual among individuals ``` ~~~ -[^note]:The syntax for all list -operations can be found in [the syntax sheat cheet](https://catalalang.github.io/catala/syntax.pdf) -or in the [language reference](./5-catala.md). +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. As an exercise, you can try implementing a new article that +complexifies even more the computation: + +~~~admonish quote title="Article 9" +The deduction granted at article 8 is capped at $8,500 for the whole household. +~~~ + +~~~admonish example title="Implementation solution for articles 7, 8 and 9" collapsible=true +```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 + # It is possible to store the structure resulting from a scope call + # (with all its output variable) into a single type. The name of this + # structure type is the name of the scope, hence the line below. + 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 +``` + +#### Article 7 + +When several individuals live together, they are collectively subject to +the household tax. The household tax owed is $1000 per individual of the household, +and half the amount per children. + + +```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 +``` +~~~ + +## 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](./2-1-basic-blocks.md), we can declare a new +test scope for the household tax computation, and execute it: + +~~~admonish success title="New test for `HouseholdTaxComputation`" +```catala +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| + } +``` + +```text +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`: + +~~~admonish abstract title="Trace of `TestHousehold`" collapsible=true +```text +$ 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! This section has not +presented features that are unique to Catala, unlike the exceptions from [the +previous section](./2-2-conditionals-exceptions.md). 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](./3-project), and misses a [lot of tips](./4-0-howto.md) about +coding in Catala but also interacting with lawyers. + +~~~~~~admonish info collapsible=true title="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. + +~~~ +{{#include ../examples/tutorial_end_2_3.catala_en}} +~~~ +~~~~~~