# AP1 · 5 — Garder un accumulateur

## Notre question

Pouvons-nous compter sans laisser une addition en attente après chaque appel ?

> **Repères.** [Slides 56 à 61](https://ap-2026.noce.fr/slides/AP1-reference.html#56) : accumulateur et récursion terminale. Poly, chap. 4 § « L'accumulateur et la récursion terminale ». Le [poly](https://ap-2026.noce.fr/poly/poly-elixir.pdf)
> reprend ces notions par écrit.

Cet atelier de réserve est autonome : aucune cellule d'un autre notebook
n'est nécessaire. Le parcours principal de la séance est la série de
carnets `ap1-01-expressions.livemd` à `ap1-05-pile-calculatrice.livemd` ;
utilisez cette fiche pour reprendre une notion ou vous entraîner
davantage, selon les indications données en cours.
Nous utilisons le moteur Elixir de Livebook ; l'installation d'Elixir
sur votre système attendra AP6.

Commencez par prévoir le résultat, puis évaluez les cellules de haut en bas.
Écrivez les fonctions demandées dans la cellule indiquée. Gardez une phrase
sur une hésitation ou une découverte dans votre carnet principal.

> 💡 Pour démarrer : L'accumulateur est un paramètre qui représente le travail déjà fait. À chaque appel, le reste à traiter diminue et ce paramètre est mis à jour. Le cas d'arrêt rend le résultat transporté.

> 💡 Nous préciserons en cours les ateliers à terminer selon notre rythme.
> Les rubriques « Pour aller plus loin » restent facultatives.
> Vos réponses serviront au bilan, sans exercice supplémentaire à inventer.

Les cellules `assert` sont des vérifications fournies : si une condition
est fausse, Livebook montre le résultat obtenu et celui attendu.
Évaluez cet import une fois, puis réévaluez votre code avant ses tests
après chaque modification.

```elixir
import ExUnit.Assertions
```

## Choisir ce que représente le paramètre (2 min)

`Tally.count(list, total)` reçoit les éléments à lire et le nombre déjà
compté. Avec un `total` initial de 0, nous calculons la taille de la liste.
Avec un `total` initial de 5, nous y ajoutons le nombre d'éléments.

Nous transmettons une nouvelle valeur au prochain appel. Nous ne modifions
pas le paramètre de l'appel courant. Prévoyez les réponses pour `([], 5)`,
`([9], 5)` et `([9, 2], 5)` dans cette cellule de texte : …

## Écrire la transition (5 min)

Le cas vide est fourni. Écrivez la clause non vide : consommez la tête,
puis appelez `count/2` avec le reste et le compteur mis à jour. L'appel
récursif doit être la dernière opération effectuée par cette clause.

Le code de l'atelier précédent n'est pas requis : le contrat est entièrement
décrit ici. N'appelez pas `length/1` ni `Enum`.

```elixir
defmodule Tally do
  def count([], total), do: total
  # Écrivez la clause non vide, avec ses deux paramètres.
end
```

```elixir
assert Tally.count([], 5) == 5
assert Tally.count([9], 5) == 6
assert Tally.count([9, 2], 5) == 7
assert Tally.count([:ok, "bonjour"], 0) == 2
```

## Comparer les deux traces (3 min)

Complétez les deux colonnes pour `count([4, 7, 2], 0)` :

| Reste à lire | Déjà compté |
| --- | --- |
| `[4, 7, 2]` | `0` |
| … | … |
| `[]` | … |

Quand le cas vide renvoie le compteur, reste-t-il une addition à effectuer
dans les appels précédents ? C'est ce que nous appelons une récursion
*terminale*. La machine virtuelle peut réutiliser le cadre d'appel.
Cette propriété ne veut pas dire que toute la mémoire du programme est constante.

Pour aller plus loin, écrivez `sum/2` avec un total initial, puis `reverse/2`
avec une liste initiale `[]`. Pour cette dernière, placez chaque tête devant
la liste accumulée : quel invariant pouvez-vous donner après deux appels ?

## Garder une trace

Sauvegardez ce notebook dans `entrainement/ap1-accumulateurs.livemd`,
en dehors du dossier collecté `AP1/`. Retrouvez la notion suivante dans
`ap1-chaines.livemd` si vous souhaitez poursuivre cet entraînement.
Le parcours principal reste la série `AP1/ap1-01-expressions.livemd`
à `AP1/ap1-05-pile-calculatrice.livemd`, où vous conservez directement
le travail demandé pour le rendu unique du cycle AP1–AP3, le
6 décembre 2026 à 23 h 59 (Paris). Il n'y a pas de deuxième série
de notebooks à rendre.

Un bout de syntaxe oublié ? Les chapitres 1 à 4 du [poly](https://ap-2026.noce.fr/poly/poly-elixir.pdf)
reprennent les formes du langage, chacune avec un exemple et son résultat ;
le cours, lui, se fait dans les carnets.

Pour toute question, vous pouvez me contacter par email :
[aurelien.noce@minesparis.psl.eu](mailto:aurelien.noce@minesparis.psl.eu).
