Introduction

Welcome to the Catala domain-specific programming language, an introductory book about Catala!

TL;DR

The Catala domain-specific language lets you annotate a legal specification with executable and deployable code in an efficient, high-assurance fashion. Automating the enforcement of a law or regulation through the use of a computer program is not neutral for the Rule of Law as well as the rights of users. Please thread lightly when considering automating anything else than tax or social benefits computation.

Contrary to a rules engine, Catala is a fully-fledged programming language with modular abstractions inspired by functional programming. But most importantly, it enables real collaboration between lawyers and computer scientists by allowing the practice of pair programming through literate programming for writing and updating the programs and their legal specifications.

Who Catala is for

Catala is not a general-purpose programming language

Catala is a domain-specific programming language, hence its use is targeted to a specific class of users and organizations.

Multi-disciplinary teams

Catala is designed to be used by teams mixing legal and computer science expertise. Indeed, automating the enforcement of a law or a regulation requires bridging the ambiguity gap of the legal text to a computer program that knows what to do in every possible situation. Bridging this ambiguity gap is one of missions of lawyers, trained in interpreting legal texts and performing legal research to come up with a decision that can be justified withing the framework of the Rule of Law.

If lawyers should be deciding what the program does, they are not trained in programming concepts and abstractions, nor do they know how to write thousands of lines of code in a clean and maintainable fashion. Hence, the role of the computer scientist is to ensure that the program automating the enforcement of a law or regulation is clean, concise, featuring correctly-scoped abstractions that prevent code duplication and ease maintenance and future changes. Moreover, the computer scientist is also responsible for deploying the program in a bigger IT system that might break its assumptions or stress its performance.

By reusing existing software engineering techniques and tools, while exhibiting lawyer-friendly concepts at its surface, Catala lets lawyers and computer scientists collaborate in a truly agile manner, going beyond the separation between development and quality assurance teams that communicate only via test cases and specification documents.

Government agencies and public service organizations

Automating the enforcement of a law or regulation through a computer program is no small task. To make sure all are treated fairly under the Rule of Law, your program should exhaustively take into account every situation described by the law or regulation. While automating only the most simple situation corresponding to a majority of users might acceptable in certain situations, it cannot be the basis for a production-ready public service. Indeed, creating a difference between an automated "simple path" and a non-automated handling of complex situation widens the digital divide, and increases confusion for users and case workers alike.

Catala shines when the goal is to automate exhaustively and with high assurance a given law or regulation, and to maintain this automation over time. The language and tooling will help you manage the growing complexity, maintenance over legal changes, corner cases and production-ready deployment inside a legacy IT system. If you are looking for a tool to make a first-level user-help chatbot backend that only answers basic questions, or a simplified model of a law for an economic study, then you should consider using other tools. On the other hand, if you are in an organization responsible for running a public service like taxes or social benefits, then you should have the means to properly engineer the computer program responsible for the automation, and use Catala to help you with it.

Because Catala compiles to mainstream programming languages like Python or C, it yields portable source code libraries that are embeddable in virtually any IT system, legacy or modern. More particularly, Catala programs can be deployed behind a Web API or embarked in a desktop application, enabling "write once, use anywhere". Hence, Catala is particularly suited to historical government agencies that have been operating their IT systems for decades in the past, and will continue to do so decades in the future.

Students and academics in CS and/or Law

Formalizing law, which is a more general term for translating law into executable computer code, has been a subject of scholarly attention for a very long time. AI & Law has historically been the umbrella community for this line of work, with three sequential trends: logic programming, ontologies, and now machine learning and especially natural language processing. While these trends have uncovered important results for formalizing law, big research questions remain. How to model complex legal provisions spanning large corpuses? Can formalizing law be automated? Can legal drafting be technologically augmented? How to detect inconsistencies or loopholes by static or dynamic analysis?

With strong roots to the research community, its commitment to open-source, its formalized semantics and its extensible compiler, Catala as a programming language is an opportunity for student learning and research projects. While teachers and students can use Catala for hands-on exploring of tax and social benefits law, researchers can use Catala programs as datasets or program a new analysis that can be readily deployed to the users of Catala.

If you're a student, a professor, or anything else actually, you're welcome to use Catala for free and contribute back to it by filing issues, proposing pull requests, or develop plugins and tooling around it.

Who this book is for

This books is primarily geared towards programmers that want to learn Catala, set up a project using it to translate some legal text into executable code, and be guided through the process. The book assume basic knowledge of functional programming idioms, and generally software engineering experience with another mainstream programming language.

If you, a programmer, work in a multidisciplinary team with one or several lawyers, it is up to you to explain to them what Catala is and how to work with it. This guide will thus also cover various topics around the collaboration between lawyers and programmers.

If you are a lawyer and stumble across this book, you are also welcome to read it, although parts of it will not be relevant to you. You might checkout instead introductory articles that set up the context around computer code, translating law to computer code and introduce the specificities of Catala:

Lawyer-friendly publications about Catala and coding the law

How to use this book

The book is organized into two parts: the user guide and the reference guide. While the user guide is meant to be read linearly and aimed at new users, the reference guide is the go-to stop for checking items about the Catala language and tooling as you're using it, whether you are a new or experienced user.

The user guide starts with Chapter 1 and the Catala equivalent of "Hello, world!" program. Chapter 2 explains the core concepts of Catala with a hands-on tutorial centered on the automation of a basic, fictional tax system. Moving onto serious business, Chapter 3 dives into the setting up of a real-world Catala project with version control, monitoring legal changes, testing, continuous integration, automated deployment, etc. Finally, Chapter 4 speeds up your learning by answering to (almost) all the questions that you'll normally stumble upon while coding the law with Catala.

In the reference guide, Chapter 5 details all the features available in the Catala language, while Chapter 6 and Chapter 7 focus on the command line interfaces and features of the two binaries that you will be working with: clerk and catala.

Source code

The source files from which this book is generated can be found on GitHub. While the contents of this book are expected to correspond to the latest version of Catala, some inconsistencies might appear. If you spot one, or have comments or suggestions about the book, please file an issue!

Getting started

Welcome to the getting started chapter! This chapter is all about setting you up for the beginning of your journey into Catala. First, you'll need to install Catala on your machine, as Catala is not a Software as a Service but rather a fully-fledged programming language toolchain. Second, you should test whether everything is OK by creating and running your first, "Hello, world!"-like Catala program.

You will get introduced to :

  • the Catala compiler catala ;
  • the Catala build system clerk;
  • the Catala IDE tooling (language plugin and formatter).

Installing Catala on your machine

Disclaimer

Currently, Catala is only available through source building. We plan to package Catala as binaries in the future, which will greatly ease the installation process.

Catala is a programming language primarily designed to be installed on your machine and run locally in your favorite development environment. Materially, Catala is comprised of several executables that together complete the tooling for the programming language:

  • the Catala compiler catala, together with the build system clerk;
  • the Catala Language Server Protocol (LSP) server catala-lsp;
  • the Catala auto formatting tool catala-format;
  • the Catala plugin for your text editor or IDE.

Under the hood, most of these executables are produced using the OCaml software toolchain, so the installation process begins with opam, the package and build system for OCaml.

The installation instructions all assume proficiency with the command line and basic knowledge about the filesystem and the general process of building executables from sources using a package manager.

The installation failed, what can I do?

If your installation failed even though you were following the installation guide, please file an issue or start a thread on the Catala community online chat.

In your issue or post, please provide:

  • your platform and operating system;
  • a log of the commands you executed with their command line output.

The installation instructions are different whether you are on an Unix-compatible system (Linux, MacOS, Windows Subsystem for Linux), or on plain Windows. Please pick the appropriate guide for your situation.

Important information

During the installation steps several prompts might occur, choosing the default option (by pressing enter each time) or answering yes (by typing y then enter) is enough.

Linux/Mac/WSL

Unless noted otherwise, the installation of the Catala tooling happens on a regular command-line terminal.

For WSL2 users

We assume all the given commands are invoked in a WSL2 environment. WSL2 can be installed by running > wsl --install in a Window's PowerShell (Windows key + R then type powershell in the prompt). WSL2 will install by default a Ubuntu-like virtual machine. Then, you may enter the WSL2 environment and the virtual machine by typing wsl in the PowerShell.

Getting opam

Install the latest version of opam (version >= 2.2), through the official installation instructions that we repeat here for convenience.

With aptitude (debian-like linux distributions):

$ sudo apt update
$ sudo apt install opam

Without aptitude:

$ bash -c "sh <(curl -fsSL https://opam.ocaml.org/install.sh)"

At this point, opam should be initialized on your machine. But it is not over, as opam needs to create a switch with a specific version of OCaml, where all the packages that we'll install later will be compiler and store. To initialize opam and create this first switch, enter the following:

$ opam init -c 4.14.2
$ eval $(opam env)

What if I already have opam?

Then you can keep your current switch for installing Catala, or create a new, specific one with opam switch create. Catala normally supports OCaml versions 4.14.X and 5.0.X.

Getting Catala

Run the following command to install the latest Catala version via opam:

$ opam pin catala.dev git+https://github.com/CatalaLang/catala -y

Once this finishes, the Catala compiler (and its build system) should be installed. You should be able to succesfully call $ catala --version in your terminal. If that's not the case, try invoking $ eval $(opam env) priorly.

Upgrading Catala

At any time, you can retrieve the latest Catala development version using these simple commands:

$ opam update
$ opam upgrade catala

This method also works for the other opam packages presented below: just replace upgrade catala by upgrade catala-lsp, etc.

Getting the LSP server (needed by the VSCode extension)

The VSCode extension requires the Catala's Language Server Protocol to be installed. This can be done by running:

$ opam pin catala-lsp.dev git+https://github.com/CatalaLang/catala-language-server -y

Getting the VSCode extension

Install VSCode and open it. Browse the extension marketplace and install the Catala extension.

For WSL2 installations

VSCode needs to reach the installed WSL environment to retrieve the Catala tools. This can be done by installing the official WSL VSCode extension. Once this is installed, you will need to load a WSL VSCode window by pressing F1 (which opens the VSCode prompt) and execute the following command WSL: Connect to WSL.

Getting the Catala code formatter

Run the following command:

$ opam pin catala-format.dev git+https://github.com/CatalaLang/catala-format

Note

This installation will take some time as it requires installing a Rust toolchain. If you already have a Rust tool chain installed (check by typing cargo in the terminal), select ignore pin depends when asked for.

Once this is installed, you may refresh your VSCode environment (F1, then Developer: Reload Window) which will notify the Catala extension that the formatter is now available. You can invoke the formatter using F1, then Format Document or by a user-defined's key-binding.

Windows

Danger

The Windows installation is currently experimental, as the Windows support for the OCaml software toolchain dates from the early 2020s.

Getting Opam

Open a PowerShell and install opam by invoking

$ Invoke-Expression "& { $(Invoke-RestMethod https://opam.ocaml.org/install.ps1) }"

Alternative opam installation methods

If an unexpected error occurs, try another opam installation method as listed on the OCaml on Windows official webpage.

Then, initialize opam:

$ opam init -c 4.14.2

Getting Catala

Currently, the opam Catala package is not directly buildable on Windows. However, the Catala's lsp server bundles a subset of Catala which is fine. This may be installed with the following command

$ opam pin git+https://github.com/CatalaLang/catala-lsp -y

Setting up the Catala LSP server

After the previous step, the Catala LSP server should be built in opam's binaries directory. In order for VSCode to be able to get it, this directory must be added to Windows' PATH environment variable.

To change the PATH environment variable, follow these instructions.

opam binary directory on Windows

The directory in question should be located in %LOCALAPPDATA%\opam\default\bin (n.b., default might be named something else such as "4.14.2", double-check the directory location).

Getting the VSCode extension

Install VSCode and open it. Browse the extension marketplace and install the Catala extension.

Getting the Catala code formatter

Currently, the code formatter is not yet available on Windows.

Creating your first Catala program

Now that you have installed the Catala tooling, you can test its correct execution with the equivalent of a Hello, world! program.

Catala programs are just text files that can be handled by any text editor/IDE. Hence, to kickstart your Catala development, we recommend you open your favorite text editor.

Text editor/IDE support

The Catala maintenance team currently only provides full support for the VSCode text editor (syntax highlighting, language server, formatter).

However the Catala community has written a number of plugins for other text editors and IDEs, whose maintenance is performed on a best-effort basis. Please contribute if you add support to your favorite text editor!

In your text editor/IDE, create a new folder for your Catala developments (for instance named catala) and inside it an empty text file (for instance named tutorial.catala_en).

Writing some specifications into a Catala file

Literate programming in Catala

Catala uses the paradigm of literate programming,

Writing your first Catala code block

Typechecking and running the Catala program

Tutorial : computing your taxes

Welcome to this tutorial, whose objective is to guide you through the features of the Catala language and teach you how to annotate a simple legislative text using the language, and get out an executable program that compute your taxes!

This tutorial does not cover the installation of Catala. For more information about this, please refer to the installation section. If you want follow this tutorial locally, read the section about creating your first program and simply copy-paste the code snippets of the tutorial into your Catala program file.

Need more information?

At any point, please refer to the Catala syntax cheat sheet or the reference guide for an exhaustive view of the syntax and features of Catala; this tutorial is rather designed to ease you into the language and its common use patterns.

There are three sections in the tutorial, that are designed to be complete in order as they cover increasingly difficult and advanced features of the language:

  • the first section is about the basic blocks of the language programs with simple data flow;
  • the second section is about what makes Catala unique: its first-class handling of conditional definitions and exceptions;
  • the third section is about scaling up the codebase with multiple functions and lists of items.

Practising the tutorial

This tutorial is designed to be an interactive experience. While reading the text of the different sections, we encourage you to create a tutorial.catala_en empty text file and fill it by copy-pasting the code snippets presented. Through this companion file, you will be able to see first-hand how the Catala typechecker and interpreter behaves on the different examples, and even make your own experiences by tweaking the code yourself.

You should be all set to begin now. Godspeed!

Basic blocks of a Catala program

In this section, the tutorial introduces the basic blocks of a Catala program : the difference between law and code, data structures, scopes, variables and formulas. By the end of the section, you should be able to write a simple Catala program equivalent to a single function with local variables whose definitions can refer to one another.

Tutorial cheat code

A recap of the tutorial section with the full code that is expected to be in your tutorial.catala_en companion file is attached at the end of this page.

Pease refer to it if you feel lost during the reading and want to have a vibes check of whether you are on track to complete your tutorial.catala_en file.

Mixing law and code

Catala is a language designed around the concept of literate programming, that is the mixing between the computer code and its specification in a single document. Why literate programming? Because it enables a fine-grained correspondance between the specification and the code. Whenever the specification is updated, knowing where to update the code is trivial with literal programming. This is absolutely crucial for enabling long-term maintenance of complex and high-assurance programs like tax or social benefits computation.

Hence, a Catala source code file looks like a regular Markdown document, with the specification written down and styled as Markdown text, with the Catala code only present in well-bounded Catala code blocks introduced by a line with ```catala and ended by a line with ```.

Before writing any Catala code, we must introduce the specification of the code for this tutorial. This specification will be based on a fictional Tax Code defining a simple income tax. But in general, anything can be used as a specification for a Catala program: laws, executive orders, court cases motivations, legal doctrine, internal instructions, technical specifications, etc. These sources can be mixed to form a complete Catala program that relies on these multiple sources. Concretely, incorporating a legal source of specification into the Catala program amounts to copy-pasting the text and formatting it in Markdown syntax inside the source code file.

Without further ado, let us introduce the first bit of specification for our fictional income tax, article 1 of the CTTC (Catala Tutorial Tax Code):

Article 1

The income tax for an individual is defined as a fixed percentage of the individual's income over a year.

The spirit of writing code in Catala is to stick to the specification at all times in order to put the code snippets where they belong. Hence, we will introduce below the Catala code snippets that translate article 1, which should be put just below article 1 in the Catala source code file.

These code snippets should describe the program that computes the income tax, and contain the rule defining it as a multiplication of the income as rate. It is time to dive into Catala as a programming language.

# We will soon learn what to write here in order to translate the meaning
# of article 1 into Catala code.

# To create a block of Catala code in your file, bound it with Markdown-style
# "```catala" and "```" delimiters. You can write comments in Catala code blocks
# by prefixing lines with "#"

# In the rest of the tutorial, when presenting Catala code snippets, it is
# assumed implicitly that you should copy-paste them into your
# tutorial.catala_en file inside a Catala code block enclosed between
# "```catala" and "```" delimiters, and placed near the article of law that
# it implements.

Setting up data structures

The content of article 1 assumes 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 in the computer code, in the form of data structures and function signatures.

Catala is a strongly-typed, statically compiled language, so all data structures and function signatures have to be explicitly declared. So, we begin by declaring the type information for the individual, the taxpayer that will be the subject of the tax computation. This individual has an income and a number of children, both pieces of information which will be needed for tax purposes :

Declaring a structure

# Data structure declarations and generally any declaration in Catala often
# does not match any specific article of law. Hence, you can put all the
# declarations at the top of your tutorial.catala_en file, before article 1.

# The name of the structure, "Individual", must start with an
# uppercase letter: this is the CamelCase convention.
declaration structure Individual:
  # In this line, "income" is the name of the structure field and
  # "money" is the type of what is stored in that field.
  # Available types include: "integer", "decimal", "money", "date",
  # "duration", and any other structure or enumeration that you declare.
  data income content money
  # The field names "income" and "number_of_children" start by a lowercase
  # letter, they follow the snake_case convention.
  data number_of_children content integer

This structure contains two data fields, income and number_of_children. 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). It is up to you to decide how to group the data together, but we advise you to aim at optimizing code readability.

Declaring an enumeration

Sometimes, the law gives an enumeration of different situations. These enumerations are modeled in Catala using an enumeration type, like:

# The name "TaxCredit" is also written in CamelCase.
declaration enumeration TaxCredit:
  # The line below says that "TaxCredit" can be a "NoTaxCredit" situation.
  -- NoTaxCredit
  # The line below says that alternatively, "TaxCredit" can be a
  # "ChildrenTaxCredit" situation. This situation carries a content
  # of type integer corresponding to the number of children concerned
  # by the tax credit. This means that if you're in the "ChildrenTaxCredit"
  # situation, you will also have access to this number of children.
  -- ChildrenTaxCredit content integer

In computer science terms, such an enumeration is called a "sum type" or simply an enum. The combination of structures and enumerations allow the Catala programmer to declare all possible shapes of data, as they are equivalent to the powerful notion of algebraic data types.

Notice that these data structures that we have declared cannot always be attached naturally to a particular piece of the specification text. So, where to put these declarations in your literate programming file? Since you will be often going back to these data structure declarations during programming, we advise you to group them together in some sort of prelude in your code source file. Concretely, this prelude section containing the data structure declaration will be your one stop shop when trying to understand the data manipulated by the rules elsewhere in the source code file.

Scopes as basic computation blocks

We've defined and typed the data that the program will manipulate. Now, we have to define the logical context in which this data will evolve. Because Catala is a functional programming language, all code exists within a function. And the equivalent to a function in Catala is called a scope. A scope is comprised of :

  • a name,
  • input variables (similar to function arguments),
  • internal variables (similar to local variables),
  • output variables (that together form the return type of the function).

For instance, article 1 declares a scope for computing the income tax:

Declaring a scope

# Scope names use the CamelCase naming convention, like names of structs
# or enums Scope variables, on the other hand, use the snake_case naming
# convention, like struct fields.
declaration scope IncomeTaxComputation:
  # The following line declares an input variable of the scope, which is akin to
  # a function parameter in computer science term. This is the piece of
  # data on which the scope will operate.
  input individual content Individual
  internal tax_rate content decimal
  output income_tax content money

The scope is the basic abstraction unit in Catala programs, and scopes can be composed. Since a function can call other functions, scopes can also call other scopes. We will see later how to do this, but first let us focus on the inputs and outputs of scopes.

The declaration of the scope is akin to a function signature: it contains a list of all the arguments along with their types. But in Catala, scope variables can be input, internal or output. input means that the variable has to be provided whenever the scope is called, and cannot be defined within the scope. internal means that the variable is defined within the scope and cannot be seen from outside the scope; it's not part of the return value of the scope. output means that a caller can retrieve the computed value of the variable. Note that a variable can also be simultaneously an input and an output of the scope, in that case it should be annotated with input output.

Once the scope has been declared, we can use it to define our computation rules and finally code up article 1!

Defining variables and formulas

Article 1 actually gives the formula to define the income_tax variable of scope IncomeTaxComputation, which translates to the following Catala code:

Article 1

The income tax for an individual is defined as a fixed percentage of the individual's income over a year.

Defining a variable

scope IncomeTaxComputation:
  definition income_tax equals
    individual.income * tax_rate

Let us unpack the code above. Each definition of a variable (here, income_tax) is attached to a scope that declares it (here, IncomeTaxComputation). After equals, we have the actual expression for the variable : individual.income * tax_rate. The syntax for formulas uses the classic arithmetic operators. Here, * means multiplying an amount of money by a decimal, returning a new amount of money. The exact behavior of each operator depends on the types of values it is applied on. For instance, here, because a value of the money type is always an integer number of cents, * rounds the result of the multiplication to the nearest cent to provide the final value of type money (see the FAQ for more information about rounding in Catala). About individual.income, we see that the . notation lets us access the income field of individual, which is actually a structure of type Individual.

Using enumerations

Similarly to struct field access, Catala lets you inspect the contents of a enumeration value with pattern matching, as it is usual in functional programming language. Concretely, if tax_credit is a variable whose type is TaxCredit as declared above, then you can define the amount of a tax credit that depends on a number of eligible children with the following pattern matching:

match tax_credit with pattern
-- NoTaxCredit: $0
-- ChildrenTaxCredit of number_of_eligible_children:
  $10,000 * number_of_eligible_children

In the branch -- ChildrenTaxCredit of number_of_eligible_children:, you know that tax_credit is in the variant ChildrenTaxCredit, and number_of_eligible_children lets you bind the integer payload of the variant. Like in a regular functional programming language, you can give any name you want to number_of_eligible_children, which is useful if you're nesting pattern matching and want to differentiate the contents of two different variant payloads.

Now, back to our scope IncomeTaxComputation. at this point we're still missing the definition of tax_rate. This is a common pattern when coding the law: the definitions for various variables are scattered in different articles. Fortunately, the Catala compiler automatically collects all the definitions for each scope and puts them in the right order. Here, even if we define tax_rate after income_tax in our source code, the Catala compiler will switch the order of the definitions internally because tax_rate is used in the definition of income_tax. More generally, the order of toplevel definitions and declarations in Catala source code files does not matter, and you can refactor code around freely without having to care about dependency order.

In this tutorial, we'll suppose that our fictional CTTC specification defines the percentage in the next article. The Catala code below should not surprise you at this point.

Article 2

The fixed percentage mentioned at article 1 is equal to 20 %.

scope IncomeTaxComputation:
  # Writing 20% is just an alternative for the decimal "0.20".
  definition tax_rate equals 20 %

Common values and computations in Catala

So far, we have seen values that have types like decimal, money, integer. One could object that there is no point in distinguishing these three concepts, as they are merely numbers. However, the philosophy of Catala is to make every choice that affects the result of the computation explicit, and the representation of numbers does affect the result of the computation. Indeed, financial computations vary according to whether we consider money amount as an exact number of cents, or whether we store additional fractional digits after the cent. Since the kind of programs Catala is designed for implies heavy consequences for a lot of users, the language is quite strict about how numbers are represented. The rule of thumb is that, in Catala, numbers behave exactly according to the common mathematical semantics one can associate to basic arithmetic computations (+, -, *, /).

In particular, that means that integer values are unbounded and can never overflow. Similarly, decimal values can be arbitrarily precise (although they are always rational, belonging to ℚ) and do not suffer from floating-point imprecisions. For money, the language makes an opinionated decision: a value of type money is always an integer number of cents.

These choices has several consequences:

  • integer divided by integer gives a decimal ;
  • money cannot be multiplied by money (instead, multiply money by decimal) ;
  • money multiplied (or divided) by decimal rounds the result to the nearest cent ;
  • money divided by money gives a decimal (that is not rounded whatsoever).

Types, values and operations

Concretely, this gives:

10 / 3 = 3.333333333...
$10 / 3.0 = $3.33
$20 / 3.0 = $6.67
$10 / $3 = 3.33333333...

The Catala compiler will guide you into using the correct operations explicitly, by reporting compiler errors when that is not the case.

Resolving typing errors on operations

For instance, typing to add an integer and a decimal gives the following error message from the Catala compiler:

┌─[ERROR]─
│
│  I don't know how to apply operator + on types integer and decimal
│
├─➤ tutorial_en.catala_en
│    │
│    │   definition x equals 1 + 2.0
│    │                       ‾‾‾‾‾‾‾
│
│ Type integer coming from expression:
├─➤ tutorial_en.catala_en
│    │
│    │   definition x equals 1 + 2.0
│    │                       ‾
│
│ Type decimal coming from expression:
├─➤ tutorial_en.catala_en
│    │
│    │   definition x equals 1 + 2.0
│    │                           ‾‾‾
└─

To fix this error, you need to use explicit casting, for instance by replacing 1 by decimal of 1. Refer to the language reference for all possible casting, operations and their associated semantics.

Catala also has built-in date and duration types with the common associated operations (adding a duration to a date, substracting two dates to get a duration, etc.). For a deeper look at date computations (which are very tricky!), look at the language reference.

Testing the code

Now that we have implemented a few articles in Catala, it is time to test our code to check that it behaves correctly. We encourage you to test your code a lot, as early as possible, and check the test result in a continuous integration system to prevent regressions.

The testing of Catala code is done with the interpreter inside the compiler, accessible with the interpret command and the --scope option that specifies the scope to be interpreted?

Why can't I test IncomeTaxComputation directly?

The reflex at this point is to execute the following command:

$ catala interpret tutorial.catala_en --scope=IncomeTaxComputation
┌[ERROR]─
│
│  This scope needs input arguments to be executed. But the Catala built-in interpreter does not have a way to retrieve input values from the command line, so it cannot execute this scope.
│  Please create another scope that provides the input arguments to this one and execute it instead.
│
├─➤ tutorial.catala_en
│   │
│   │   input individual content Individual
│   │         ‾‾‾‾‾‾‾‾‾‾
└─

As the error message says, trying to interpret directly IncomeTaxComputation is like trying to compute the taxes of somebody without knowing the income of the person! To be executed, the scope needs to be called with concrete values for the income and the number of children of the individual. Otherwise, Catala will complain that input variables of the scope are missing for the interpretation.

The pattern for testing make use of concepts that will be seen later in the tutorial, so it is okay to take part of the following as some mysterious syntax that performs what we want. Basically, we will be creating for our test case a new test that will pass specific arguments to IncomeTaxComputation which is being tested:

Defining a test

declaration scope Test:
  # The following line is mysterious for now
  output computation content IncomeTaxComputation

scope Test:
  definition computation equals
    # The following line is mysterious for now
    output of IncomeTaxComputation with {
      # Below, we pass the input variables for "IncomeTaxComputation"
      -- individual:
        # "individual" has a structure type, so we need to build the
        # structure "Individual" with the following syntax
        Individual {
          # "income" and "number_of_children" are the fields of the structure;
          # we give them the values we want for our test
          -- income: $20,000
          -- number_of_children: 0
        }
    }

This test can now be executed through the Catala interpreter:

$ catala interpret tutorial.catala_en --scope=Test
┌─[RESULT]─
│ computation = IncomeTaxComputation { -- income_tax: $4,000.00 }
└─

We can now check that $4,000 = $20,000 * 20%; the result is correct.

Test, test, test!

Use this test to regularly play with the code during the tutorial and inspect its results under various input scenarios. This will help you understand the behavior of Catala programs, and spot errors in your code 😀

You can also check that there is no syntax or typing error in your code, without testing it, with the following command:

$ catala typecheck tutorial.catala_en
┌─[RESULT]─
│ Typechecking successful!
└─

Checkpoint

This concludes the first section of the tutorial. By setting up data structures like structure and enumeration, representing the types of scope variables, and definition of formulas for these variables, you should now be able to code in Catala the equivalent of single-function programs that perform common arithmetic operations and define local variables.

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 individual content Individual
  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

The fixed percentage mentioned at article 1 is equal to 20 %.

```catala
scope IncomeTaxComputation:
  label article_2
  definition tax_rate equals 20%
```

## 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
        }
    }
```

Conditional definitions and exceptions

In this section, the tutorial introduces the killer feature of Catala when it comes to coding the law: exceptions in the definitions of variables. By the end of the section, you should understand the behavior of computations involving exceptions, and be able to structure groups of variable definitions according to their exceptional status and relative priority.

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 individual content Individual
  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

The fixed percentage mentioned at article 1 is equal to 20 %.

```catala
scope IncomeTaxComputation:
  label article_2
  definition tax_rate equals 20%
```

## 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
        }
    }
```

Conditional definitions and exceptions

Specifications coming from legal text do not always neatly divide up each variable definition into its own article. Sometimes, and this is a very common pattern, a later article redefines a variable already defined previously, but with a twist in a certain exceptional situation. For instance, article 3 of CTTC:

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 %.

This article actually gives another definition for the fixed percentage, which was already defined in article 2. However, article 3 defines the percentage conditionally to the individual having more than 2 children. How to redefine tax_rate? Catala allows you precisely to redefine a variable under a condition with the under condition ... consequence syntax between the name of the variable being defined and the equals keyword:

Defining a variable conditionally

scope IncomeTaxComputation:
  definition tax_rate under condition
    individual.number_of_children >= 2
  consequence equals 15 %

What does this mean? If the individual has more than two children, then tax_rate will be 15 %. Conditional definitions let you define your variables piecewise, one case at a time; the Catala compiler stitches everything together for execution. More precisely, at runtime, we look at the conditions of all piecewise definitions for a same variable, and pick the one that is valid.

Conflict between definitions

But what happens if no conditional definition is valid at runtime? Or multiple valid definitions at the same time? In these cases, Catala will abort execution and return an error message like the one below:

┌─[ERROR]─
│
│  During evaluation: conflict between multiple valid consequences for assigning the same variable.
│
├─➤ tutorial_en.catala_en
│     │
│     │   definition tax_rate equals 20 %
│     │                                      ‾‾‾‾
├─ Article 2
│
├─➤ tutorial_en.catala_en
│     │
│     │   consequence equals 15 %
│     │                      ‾‾‾‾
└─ Article 3

If the specification is correctly drafted, then these error situations should not happen, as one and only one conditional definition should be valid at all times. Here, however, our definition of tax_rate conflicts with the more general definition that we gave above. To correctly model situations like this, Catala allows us to define precedence of one conditional definitions over another. It is as simple as adding exception before the definition. For instance, here is a more correct version of the code for article 3:

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 %.

Defining an exception for a variable

scope IncomeTaxComputation:
  exception definition tax_rate under condition
    individual.number_of_children >= 2
  consequence equals 15 %

With exception, the conditional definition at article 3 will be picked over the base case at article 1 when the individual has two children or more. This exception mechanism is modeled on the logic of legal drafting: it is the key mechanism that lets us split our variables definition to match the structure of the specification. Without exception, it is not possible to use the literate programming style. This is precisely why writing and maintaining computer programs for taxes or social benefits is very difficult with mainstream programming languages. So, go ahead and use exception as much as possible, since it is a very idiomatic Catala concept.

How are exceptions computed?

When defining exceptions in your Catala code, it is importand to understand precisely their underlying semantics, i.e. what will be the end result of the computation. The semantics of Catala are formally defined and based on prioritized default logic, which translates intuitively to the following algorithm describing how to compute exceptions:

  1. Gather all definitions (conditional or not) for a given variable;
  2. Among these definitions, check all that apply (whose conditions evaluate to true):
    • If no definition apply, the program crashes with an error ("no definitions apply");
    • If only one definition applies, then pick it and continue the execution of the program;
    • If multiple definitions apply, then check their priorities:
      • If there exists one definition that is an exception to all the others that apply, pick it and continue the execution of the program;
      • Otherwise, the program crashes with an error ("conflicting definitions").

As described above, putting exception in a Catala program alters the behavior of the program, by providing a priority between conditional definitions of a variable that Catala can use at execution time when hesitating between multiple definitions that apply at the same time. So far, we have seen a very simple situation with one base definition (in article 2) and a single exception (in article 3). But the exception mechanism can be much broader and help set different priority lines among dozens of different conditional definitions for a same variable. Let us explore this mechanism on a more complex example.

Dealing with multiple exceptions

It is frequent in legal text that an article setting up a general rule is followed by multiple articles defining exceptions to the base rule. Additionally to article 3 and the reduced tax rate for large families, the CTTC (Catala Tutorial Tax Code) indeed defines a tax exemption for low-income individuals, that we can encode as another exception to the definition of the tax rate in article 2:

Article 4

Individuals earning less than $10,000 are exempted of the income tax mentioned at article 1.

scope IncomeTaxComputation:
  exception definition tax_rate under condition
    individual.income <= $10,000
  consequence equals 0 %

But then, what happens when testing the code with an individual that earns less than $10,000 and has more than 2 children?

Conflicting definitions

The program execution yields the following error at runtime:

┌─[ERROR]─
│
│  During evaluation: conflict between multiple valid consequences for assigning the same variable.
│
├─➤ tutorial_en.catala_en
│     │
│     │   consequence equals 15 %
│     │                      ‾‾‾‾
├─ Article 3
│
├─➤ tutorial_en.catala_en
│     │
│     │   consequence equals 0 %
│     │                      ‾‾‾
└─ Article 4

In this situation, both conditional definitions from article 3 and article 4 apply, but also the base definition from article 2. We know article 3 and article 4 are exceptions to article 2, hence they both have priority over it. But we don't know which definition has priority between article 3 and article 4, hence the error message above!

In this situation, we need to prioritize the exceptions between each other.

Here, because article 4 follows article 3, and because it is more favorable to the taxpayer to pay $0 in tax rather than 15 % of their income, we can make the legal decision to prioritize the exception of article 4 over the exception of article 3. Now, let us see how to write that with Catala. Because article 2 is the base case for the exception of article 3, and article 3 is the base case for the exception of article 4, we need to give the definitions of tax_rate at articles 2 and 3 an explicit label so that the exception keywords in article 3 and 4 can refer to those labels:

Pointing exceptions to specific labels

Article 2

The fixed percentage mentioned at article 1 is equal to 20 %.

scope IncomeTaxComputation:
  # The keyword "label" introduces the name of the label itself, here
  # "article_2".
  label article_2 definition tax_rate equals 20 %

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 %.

scope IncomeTaxComputation:
  # This definition is preceded by two indications:
  # * it has its own label, "article_3";
  # * this definition is an exception to the definition labeled "article_2".
  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.

scope IncomeTaxComputation:
  label article_4 exception article_3
  definition tax_rate under condition
    individual.income <= $10,000
  consequence equals 0 %

Thanks to labels, we can define chains of exceptions, where each definition is the exception to the previous one, and the base case for the next one. This pattern is the most usual in legal texts, and its behavior is straightfoward: when multiple definitions apply, pick the one with the highest priority in the chain. Here's a representation of the exception chain in our example so far:

graph LR;
A2["`article_2`"]
A3["`article_3`"]
A4["`article_4`"]
A2-->A3
A3-->A4

But sometimes, it's not possible to arrange exceptions in a chain, since legal interpretation leads to different branches of exceptions.

Branches of exceptions

It may be difficult to see why some legal situations may lead to different branches of exceptions. Let us provide an example with a new article of the CTTC:

Article 5

Individuals earning more than $100,000 are subjects to a tax rate of 30%, regardless of their number of children.

scope IncomeTaxComputation:
  label article_5 exception article_3
  definition tax_rate under condition
    individual.income > $100,000
  consequence equals 30 %

Now, article 3 has two exceptions : article 4, and article 5. These two exceptions have the following conditions:

  • Article 4: income less than $10,000 ;
  • Article 5: income more than $100,000.

Displaying the exception branches

As the codebase grows, it becomes more and more difficult to visualized all the conditional definitions of a variable as well as the prioritization between them. To help, the Catala compiler can display the exception branches with the following command:

$ catala exceptions tutorial.catala_en --scope=IncomeTaxComputation --variable=tax_rate
┌[RESULT]─
│ Printing the tree of exceptions for the definitions of variable "tax_rate" of scope "IncomeTaxComputation".
└─
┌─[RESULT]─
│ Definitions with label "article_2":
│
├─➤ tutorial.catala_en
│    │
│    │   label article_2 definition tax_rate equals 20 %
│    │   ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
└─ Title
   └─ Article 2
┌─[RESULT]─
│ Definitions with label "article_3":
│
├─➤ tutorial.catala_en
│    │
│    │   label article_3 exception article_2 definition tax_rate under condition
│    │   ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
└─ Title
   └─ Article 3
┌─[RESULT]─
│ Definitions with label "article_4":
│
├─➤ tutorial.catala_en
│    │
│    │   label article_4 exception article_3 definition tax_rate under condition
│    │   ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
└─ Title
   └─ Article 4
┌─[RESULT]─
│ Definitions with label "article_5":
│
├─➤ tutorial.catala_en
│    │
│    │   label article_5 exception article_3 definition tax_rate under condition
│    │   ‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
└─ Title
   └─ Article 5
┌─[RESULT]─
│ The exception tree structure is as follows:
│
│ "article_2"───"article_3"──┬──"article_5"
│                            │
│                            └──"article_4"
└─

Theoretically, since the exceptions of article 4 and article 5 are not prioritized with each other, they could both apply at the same time and conflict. However, since the income cannot be both less than $10,000 and greater than $100,000, the conflict cannot happen in practice. Hence, it is not necessary to prioritize the two exceptions, since they live in mutually exclusive conditional branches. It is then possible to extend these branches separately, for instance with a new article of the CTTC:

Article 6

In the overseas territories, the tax rate for individuals earning more than $100,000 specified at article 5 is reduced to 25 %.

This article introduces a new bit of information about the tax computation: are we in an overseas territory or not? We can model it with a new input to the scope IncomeTaxComputation, leading to a revised scope declaration:

Revised scope declaration

declaration scope IncomeTaxComputation:
   input individual content Individual
   input overseas_territories content boolean
   internal tax_rate content decimal
   output income_tax content money

With this new input variable, the code for article 6 is as follows:

scope IncomeTaxComputation:
  label article_6 exception article_5
  definition tax_rate under condition
    individual.income > $100,000 and overseas_territories
  consequence equals 25 %

Exceptions do not inherit conditionals from their base case

Note that in the condition for defining tax_rate in article 6, we have repeated the condition individual.income > $100,000 in conjunction with the new clause overseas_territories. In our fictional CTTC, the text of article 6 is gently worded and explicitly reminds us that this exception to article 5 only applies in the situations that also trigger article 5 (where the income is greater than $100,000).

However, the legal text can sometimes omit this key information, or make it implicit, creating a danger of putting the wrong conditional in the Catala code in presence of exception branches. Suppose we had omitted the income condition in the code for article 6:

scope IncomeTaxComputation:
  label article_6 exception article_5
  definition tax_rate under condition
    overseas_territories
  consequence equals 25 %

With this code, the article 6 definition would have applied in overseas territories for all individuals, including those earning less than $100,000! Indeed, exceptional definitions in Catala do not inherit the conditions of their base case: the condition of article 6 does not inherit the condition of article 5, we need to repeat it in article 6 if we want to have the correct activation pattern.

Finally, we can recap the collection of exception branches as a tree of exceptions for our example:

graph LR;
A2["`article_2`"]
A3["`article_3`"]
A4["`article_4`"]
A5["`article_5`"]
A6["`article_6`"]
A2-->A3
A3-->A4
A3-->A5
A5-->A6

Grouping conditional definitions together for exceptions

So far, we have seen how to define exception chains and mutually exclusive exception branches. But there is a very common pattern that introduces yet another exceptional shenanigan. Suppose than in the year 2000, a big tax reform changes the base taxation rate of article 2 with a slight increase:

Article 2 (new version after 2000)

The fixed percentage mentioned at article 1 is equal to 21 %.

Now, there are several strategies to deal with legal updates in Catala, that are summed up in the how to section of this book. But here, we'll suppose that we want both versions of the law (before and after 2000) to coexist in the same Catala program. This choice leads us to introduce the current date as a new input of the scope IncomeTaxComputation:

Revised scope declaration

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

This current_date variable will allow us to introduce mutually exclusive conditional definitions for the two different verions of article 2, each one activating only before of after the year 2000. Note that is the two definitions of article 2 were not mutually exclusive, they could conflict with each other, forcing you to prioritize between them and change the shape of the overall exception tree by introducing another layer of exception. However, we want in this cas those two base definitions of article 2 to collectively be the base case for all subsequent exceptions in the exception tree of tax_rate! In a nutshell, we want the following exception tree:

graph LR;
subgraph article_2
direction TB
A2["`article_2 (before 2000)`"]
A2bis["`article_2 (after 2000)`"]
end
A3["`article_3`"]
A4["`article_4`"]
A5["`article_5`"]
A6["`article_6`"]
A2~~~A2bis
article_2-->A3
A3-->A4
A3-->A5
A5-->A6

Catala is able to represent this exception tree, by grouping together the two conditional definitions to article 2. Indeed, since article 3 is an exception to the label article_2, it suffices to give the same label article_2 to the two conditional definitions of the two versions of article_2:

Grouping mutually exclusive conditional definitions

Article 2 (old version before 2000)

The fixed percentage mentioned at article 1 is equal to 20 %.

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 % %.

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 %

By using the definition grouping mechanism along with exception branches, Catala is able to express a wide range of legal text logic, and helps keeping the code alongside its specification.

Checkpoint

This concludes the second section of the tutorial. In Catala, variables can be defined piece-wise, each piece of definition being activated by a condition. When multiple conditions apply, one can prioritize the conditional definitions using the exception and label keywords to form exception trees able to capture the complex logic behind the legal texts while matching their structure.

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%
```

## 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|
    }
```

Going modular with lists

In this section, the tutorial tackles a common pattern that significantly increases the complexity of a codebase: the need to deal with lists and rules 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.

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%
```

## 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|
    }
```

Making a household from a list of invidivuals

Previously, the Catala Tutorial Tax Code (CTTC) has defined an income tax for each individual and their children. But now, the CTTC is becoming greedier as a new, separate tax similar to Thatcher's infamous poll tax. At its inception, the household tax is such that each individual in a household is taxed a fixed sum, with a reduced rate for the children:

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.

Now, implementing this in Catala requires going beyond the IncomeTaxComputation scope that we used earlier. Indeed, this new tax requires a new scope, HouseholdTaxComputation! While it is fairly evident that the output of this new scope should be the household_tax, its input is the collection of individuals that make up the household.

Fortunately, Catala has a built-in type for collection of things, called list, even though it behaves more like an array in traditionnal Computer Science jargon.

Declaring a new scope with a list input

declaration scope HouseholdTaxComputation:
  # The syntax "list of <X>" designates the type whose values are lists of
  # elements with type <X>.
  input individuals content list of Individual
  output household_tax content money

To define household_tax, we must now:

  1. count the number of individuals in individuals;
  2. count the number of children in each individual and add these counts together;
  3. multiply these counts by the right amount of tax.

We will perform each one of these steps in the body of the definition of household_tax, in the scope HouseholdTaxComputation, using local variables.

internal scope variables and local variables in definitions

When a variable definition gets complex like above, it is often useful to separate each step by defining intermediate variables. There are two ways of doing that.

First, you can declare inside the scope declaration an extra scope variable with the label internal instead of input or output, as seen in the first section of the tutorial.

Second, if you are confident that you will only need the intermediate variable in the narrow context of a single scope variable definition, you can use a local variable inside the definition of the scope variable. These local variables are introduced and used with the following syntax:

# The following line defines local variable "x" as begin equal to 4 * 5
let x equals 4 * 5 in
# We can then use "x" after the "in" keyword in the rest of the code
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 (the syntax for all list operations can be found in the syntax sheat cheet or in the language reference). 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 indicates that if the list of individuals is empty, then the integer 0 should be returned. Finally, we can piece steps 1 and 2 for the step 3 which computes the amount of tax:

Computing the lenght of a list and aggregating amounts

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
    * (
      # "number_of_individuals" is an integer, but money can only be multiplied
      # by decimals: we need to explicitly cast before using the value
      decimal of number_of_individuals
      + decimal of number_of_children / 2.0
    )

This implementation of article 7 is fairly direct and concise. It does the job, but notice a subtle shift between the text of article 7 and its Catala implementation: rather than aggregating separately the contribution of each individual and their children to the household tax, we count all individuals on one side, and all children on the other side. Addition is commutative and associative so this shift yields the same result. However, not following the spirit of the law in the implementation might not be future-proof, as we'll see just below...

Refactoring to account for evolving requirements

Translating legal texts into executable code is often an emotional rollercoaster, as new requirements in later articles may completely break the invariants and structure of the implementation you used in earlier articles. Today, the Catala Tutorial Tax Code (CTTC) will be harsh on us, with the following fateful article:

Article 8

The amount of income tax paid by each individual can be deducted from the share of household tax owed by this individual.

Quickly, we realize that to be able to deduct correctly the income tax for each individual, we need to first compute its individual share of the household tax, which we have not done in the implementation of article 7. Refactoring is needed!

Is it OK to refactor earlier code when coding a new article?

Yes it is!

Theoretically, as Catala lets you structure the code by matching the structure of the legal text, adding new articles should not require changes in earlier blocks of code. This is the case for instance when a new article defines an exception to the base case of a variable, as we've experimented in the second section of the tutorial.

But adding exceptions is not the only things new articles can introduce. In this case, we see that article 8 makes explicit a computation step that was implicit or hidden in article 7 (namely, the computation of the share of household tax for each individual). Making this computation step explicit implies giving it a first-class status with a Catala concept (a variable, a scope, etc.), which may not have been the case in the Catala code written before. Hence, it is normal to refactor earlier code to code up the new article 8.

However, the goal of the refactoring is always to match up as precisely as possible the computation steps and the articles they are based on.

Now, there are several strategies to implement article 8, but not all are legally correct. One strategy could be to compute the total amount of income tax owed by all the individuals in the household, and substract that total amount of income tax from the the totam amount of household tax to perform the deduction. However, this strategy is incorrect, because the household tax deduction for one individual is implicitly capped by the amount of household tax due for this individual! This capping introduces a non-linearity in the formula that prevents rearranging the additions and substractions while keeping the same results in all configurations.

So, we are stuck with explicitly decomposing the household tax computation into two steps: first, computing the share of household tax owed by each individual, and then aggregating the result of the first step for all individuals of the household. Naturally, the existing scope HouseholdTaxComputation is where the second step will happen. But where to put the first step?

As Catala is a functional programming language, we could define an internal variable of the scope HouseholdTaxComputation that acts as a function to associate to each individual the share of household tax owed.

Declaring, defining and using a variable that is a function

The scope declaration could be modified like this:

declaration scope HouseholdTaxComputation:
  input individuals content list of Individual

  internal share_household_tax content money
    # The following line introduces a parameter to the variable, turning
    # it into a function. "individual" is set as the name of the parameter,
    # a name that is then enforced everywhere in the function definitions.
    # Indeed, lawyers reading Catala code have trouble with function parameters
    # changing names throughout the code.
    depends on individual content Individual
  output household_tax content money

Then, the definition of household_tax could be done as follows next to article 7:

scope HouseholdTaxComputation:
  # The definition refers to the function parameter with "of individual"
  definition share_household_tax of individual equals
     $10,000 * (1.0 + decimal of individual.number_of_children / 2.0)

  # To aggregate the shares, we call the function "share_household_tax"
  # on all the individuals of the input.
  definition household_tax equals
    sum money share_household_tax of individual
      for individual among individuals

This refactoring works for making explicit the computation step of the individual share of household tax in article 7, but it is not the most future-proof strategy. Indeed, as it already happened for article 8, subsequent articles are likely to introduce refinements and exceptions for this share of household tax. It is possible to have conditional definitions and exceptions for variables that are functions, but it is preferable to use a fully-fledged scopes instead. The scope is more readable by lawyers and has better convenient features to add input and output parameters, define exceptions for its local variables, etc.

Hence, we will drop the function variable share_household_tax presented above, and instead opt for creating a brand new scope for computing the share of household tax owed by an individual, HouseholdTaxIndividualComputation.

The missing scope : household tax computation for the individual

The new scope, HouseholdTaxIndividualComputation, will have as input one individual and return as a result the amount of household tax held. However, because of article 8, the scope will also need to compute the amount of income tax owed by the individual, to deduct it from the household tax. The call graph between scopes will then be the following:

%%{init: {"flowchart": {"htmlLabels": true}} }%%
graph TD
    A["`HouseholdTaxComputation`"]
    B["`HouseholdTaxInvidualComputation`"]
    C["`IncomeTaxComputation`"]
    A-- calls multiple times -->B
    B-- calls one time -->C

Hence, we will also need as input of HouseholdTaxIndividualComputation the inputs necessary for the IncomeTaxComputation scope of the previous section of the tutorial: overseas_territory and current_date This gives the following scope declaration:

Initial declaration of HouseholdTaxIndividualComputation

declaration scope HouseholdTaxIndividualComputation:
  input individual content Individual
  input overseas_territories content boolean
  input current_date content date

  output household_tax content money

Now, we know that we'll need to call IncomeTaxComputation exactly one time to compute the deduction for household_tax. There is a bespoke method designed for lawyer-readbility to do exactly that in Catala!

Declaring a static sub-scope call and defining the sub-scope call's inputs

# The single, static sub-scope call to "IncomeTaxComputation" has to be
# declared in "HouseholdTaxIndividualComputation", so we repeat the
# scope declaration here with a new line.
declaration scope HouseholdTaxIndividualComputation:
  input individual content Individual
  input overseas_territories content boolean
  input current_date content date

  # The following line declares a static, single call to the sub-scope
  # "IncomeTaxComputation" with the name "income_tax_computation".
  income_tax_computation scope IncomeTaxComputation

  output household_tax content money

scope HouseholdTaxIndividualComputation:
  # Inside a "scope" block, we have to define the arguments to the sub-scope
  # call "income_tax_computation": "individual", "overseas_territories" and
  # "overseas_territories".
  definition income_tax_computation.individual equals
    individual
  # The "individual" given as an argument to "income_tax_computation",
  # which is the call to "IncomeTaxComputation", is the same "individual"
  # that is the input to "HouseholdTaxIndividualComputation".
  definition income_tax_computation.overseas_territories equals
    overseas_territories
  # These lines can appear totological but they are essential for plugging
  # scopes to sub-scopes in an non-ambiguous way. It is implicit that we evaluate
  # the income tax for deduction at the same date as we evaluate the amount of
  # household tax, but this line makes it explicit. Sometimes, you might want
  # to call the income tax computation at an earlier date (like "current_date
  # - 5 year") because of a legal requirement, and this is where you specify
  # this!
  definition income_tax_computation.current_date equals
    current_date

That's it, the sub-scope call has been completely set up! The result is now accessible at income_tax_computation.income_tax, since "income_tax" is the output variable of the sub-scope IncomeTaxComputation.

At this point, it would be easy to define 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:

Defining multiple states for the same variable

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 owzed 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:

Calling a sub-scope dynamically

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. As an exercise, you can try implementing a new article that complexifies even more the computation:

Article 9

The deduction granted at article 8 is capped at $8,500 for the whole household.

Implementation solution for articles 7, 8 and 9

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 $10,000 per individual of the household, and half the amount per children.

scope HouseholdTaxIndividualComputation:
  definition household_tax equals
    $10,000 * (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.

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.

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, we can declare a new test scope for the household tax computation, and execute it:

New test for HouseholdTaxComputation

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

$ 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. 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

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 $1000 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|
    }
```

Setting up a Catala project

Directory structure and configuration

Test and continuous integration workflow

Compilation and deployment

External modules and compiler plugins

FAQ: How to code the law?

After installing Catala, doing the tutorial and setting up your project environment, you should be on your way to start your turning-law-into-code project. However, you might still have a number of your questions unanswered, and we have you covered. This chapter tries to answer to all the common questions users have about turning law into code in general, and Catala in particular.

General questions

What is pair programming for coding the law?

What is literate programming for coding the law?

Why shouldn't I use any programming language that I like to code the law?

Can we use Large Language Models (LLMs) to translate the law into code?

Can every law be formalized?

Catala-specific questions

Booleans and conditions

Money and rounding

In catala, monetary values are represented as an integer number of cents.

A calculation with the catala money type always result in an amount rounded to the nearest cent. This means, that, when performing intermediate computations on money, rounding must be considered by the programmer at each step. This aims at making review by domain experts easier, since for each intermediate value, they can follow along and perform example computations with a simple desk calculator.

The round of builtin will round to the nearest monetary unit (e.g. euro or dollar).

To round an amount to an arbitrary multiple of a cent, perform a multiplication with that multiple, round the amount and divide it by the same amount.

Example: rounding to the nearest multiple of 10 cents

declaration scope Rounding10Cents:
  output result content money

scope Rounding10Cents:
  definition result equals
    round of ($4.13 * 10.) / 10.
$ clerk run round.catala_en --scope Rounding10Cents
[0/1] <catala> interpret Rounding10Cents ⇐ _build/round.catala_en
┌─[RESULT]─
│ result = $4.10
└─

Rounding up or down

To round up or down, add or subtract half a unit before performing the computation and rounding.

Example

To compute a tax amount that is defined as 0.5% of a gross amount (here $149.26) rounded down to the nearest cent

declaration scope Rounding:
  output tax_amount content money

scope Rounding:
  definition tax_amount equals
    money of
      (
        round of
          (
            ((decimal of $149.26) * 0.5% * 100.0) - 0.5
          )
        / 100.
      )

This is a bit of a mouthful, but can be made more readable by introducing a function.

declaration scope Rounding:
  output tax_amount content money
  internal round_down_cents content money depends on amount_decimal content decimal

scope Rounding:
  definition tax_amount equals
    round_down_cents of (decimal of $149.26 * 0.5%)

  definition round_down_cents of amount_decimal equals
    money of ((amount_decimal * 100.0 - 0.5) / 100.)

Besides being more readable, this has the benefit of making it more obvious that any computation that requires keeping a fractional number of cents should be performed on decimals, and converted to a monetary amount at the end.

The Catala language

The catala compiler

The clerk build system