catala/examples/tutorial/tutorial_en.catala_en
2020-11-30 10:55:27 +01:00

237 lines
8.3 KiB
Plaintext

@@The Catala language tutorial@@
Welcome to this tutorial, whose objective is to guide you through the features
of the Catala language and trach you how to annotate a legislative text using
the language. This document is addressed primarily to developers or people that
have a programming background. It will use terms and jargon that might be
unintelligible for lawyers in general.
@@Literate programming@@+
To begin writing a Catala program, you must start from the text of the
legislative source that will justify the code that you will write. Concretely,
that means copy-pasting the text of the law into a Catala source file and
formatting it according so that Catala can understand it.
You can write any kind of plain text in Catala, and it will be printed as is
in PDF or HTML output. Keep in mind however that one line in the source file
corresponds to a paragraph in the output. Catala allows you to declare section
or subsection headers as it is done here, but the fundamental division unit is
the article. Let's analyse a fictional example that defines an income tax.
@Article 1@
The income tax for an individual is defined as a fixed percentage of the
individual's income over a year.
/*
# This is a placeholder comment, the code for that article should go here
*/
We will now proceed to encode the algorithmic content of this article using
the Catala language. To do that, we will intertwine short snippets of code
between the sentences of the legislative text. Each snippet of code should
be as short as possible and as close as possible to the actual sentence that
justifies the code.
@@Defining a fictional income tax@@+
The content of article 1 uses a lot of implicit context : there exists an
individual with an income, as well as an income tax that the individual has
to pay each year. Even if this implicit context is not verbatim in the law,
we have to explicit it for programming purposes. Concretely, we need a
"metadata" section that defines the shape and types of the data used
inside the law.
Let's start our metadata section by declaring the type information for the
individual and the income tax computation:
@@Begin metadata@@
/*
declaration structure Individual:
data income content amount
declaration structure Article1:
data fixed_percentage content decimal
data income_tax content amount
*/
@@End metadata@@
Each of this declaration is a structure, containing one or more data fields.
Structures are useful to group together data that goes together. Usually, you
get one structure per concrete object on which the law applies (like the
individual), but also one structure for each article that defines quantities
(like the article 1). It is up to you to decide how to group the data together,
but you should aim to optimize code readability.
Sometimes, the law gives an enumeration of different situations. These
enumerations are modeled in Catala using an enumeration type, like:
@@Begin metadata@@
/*
declaration enumeration TaxCredit:
-- NoTaxCredit
-- ChildrenTaxCredit content integer # the integer corresponds
# to the number of children
*/
@@End metadata@@
We've defined and typed the data that the program will manipulate. Now we have
to define the logical context in which these data will evolve. This is done in
Catala using "scopes". Scopes also have to be declared in metadata, so here we
go:
@@Begin metadata@@
/*
declaration scope IncomeTaxComputation:
context individual content Individual
context article1 content Article1
*/
@@End metadata@@
This scope declaration says that whenever we're in the scope
"IncomeTaxComputation", then we have access to two elements in context,
namely the individual's data and the data defined by article 1. We will be
able to refer to the lowercase variables in our code, either to use them or to
define them or one of their part.
We now have everything to annotate the contents of article 1, which is copied
over below.
@Article 1@
The income tax for an individual is defined as a fixed percentage of the
individual's income over a year.
/*
scope IncomeTaxComputation:
definition article1.income_tax equals
invidual.income * article1.fixed_percentage
*/
In the code, we are defining inside our scope the amount of the income tax
according to the formula described in the article. When defining formulaes,
you have access to all the usual arithmetic operators. But what is the value
of that fixed percentage? Often, precise values are defined elsewhere in the
legislative source. Here, let's suppose we have:
@Article 2@
The fixed percentage mentionned at article 1 is equal to 20 %.
/*
scope IncomeTaxComputation:
definition article1.fixed_percentage equals 20 %
*/
You can see here that Catala allows definitions to be scattered throughout
the annotation of the legislative text, so that each
definition is as close as possible to its location in the text.
@@Conditional definitions@@
So far so good, but now the legislative text introduces some trickyness. Let us
suppose the third article says:
@Article 3@ If the individual is in charge of 2 or more children, then the fixed
percentage mentionned at article 1 is equal to 15 %.
/*
# How to redefine article1.fixed_percentage?
*/
This article actually gives another definition for the fixed percentage, which
was already defined in article 2. However, article 3 defines the percentage
conditionnally to the individual having more than 2 children. Catala allows
you precisely to redefine a variable under a condition:
/*
scope IncomeTaxComputation:
definition article1.fixed_percentage under condition
individual.number_of_children >= 2
consequence equals 15 %
*/
When the Catala program will execute, the right definition will be dynamically
chosen by looking at which condition is true. A correctly drafted legislative
source should always ensure that at most one condition is true at all times.
However, if it is not the case, Catala will let you define a precedence on the
conditions, which has to be justified by the law.
@@Functions@@
Catala lets you define functions anywhere in your data. Here's what it looks
like in the metadata definition when we want to define a two-brackets tax
computation:
@@Begin metadata@@
/*
declaration structure TwoBrackets:
data breakpoint content amount
data rate1 content decimal
data rate2 content decimal
declaration scope TwoBracketsTaxComputation :
context brackets content TwoBrackets
context tax_formula content amount depends on amount
*/
@@End metadata@@
And in the code:
@Article4@ The tax amount for a two-brackets computation is equal to the amount
of income in each bracket multiplied by the rate of each bracket.
/*
scope TwoBracketsTaxComputation :
definition tax of income equals
if income <= breakpoint then
income * rate1
else (
breakpoint * rate1 + (income - breakpoint) * rate2
)
*/
@@Scope inclusion@@
Now that we've defined our helper scope for computing a two-brackets tax, we
want to use it in our main tax computation scope.
@Article 5@ For individuals whose income is greater than $100,000, the income
tax of article 1 is computed with a two-brackets system.
/*
declaration scope IncomeTaxComputation:
# The scope inclusion has to be added in the scope declaration
context two_brackets_for_rich scope TwoBracketsTaxComputation
scope IncomeTaxComputation :
definition article1.income_tax under condition
individual.income >= $100,000
consequence equals
two_brackets_for_rich.tax of individual.income
*/
Scope inclusion also comes with a syntactic sugar for quickly and conditionnaly
connecting context quantities :
@@Begin metadata@@
/*
declaration scope ExemptedOfTax:
context article1 content Article1
*/
@@End metadata@@
@Article 6@
Individuals earning less than $10,000 are exempted of the income tax mentionned
at article 1.
/*
scope ExemptedOfTax :
definition article1.income_tax equals $0
declaration scope IncomeTaxComputation:
# The scope inclusion has to be added in the scope declaration
context tax_exempt scope ExemptedOfTax
scope IncomeTaxComputation:
definition article1.income_tax under condition
individual.income <= $10,000
consequence equals
tax_exempt.article1.income_tax
*/
This snippet of code actually brings the definition of article1.income_tax of
ExemptedOfTax into the IncomeTaxComputation scope, prefixing it with the
"income under $10,000" condition.