# AP1 · 6 — Lire des préfixes dans une chaîne

## Notre question

Pouvons-nous consommer un texte comme nous avons consommé une liste ?

> **Repères.** [Slides 62 à 69](https://ap-2026.noce.fr/slides/AP1-reference.html#62) : préfixes de chaînes. Poly, chap. 1 § « Les chaînes » et chap. 2. 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 : Le motif `"A" <> rest` reconnaît le préfixe fixe `"A"` puis nomme ce qui suit. Le motif `""` traite la chaîne vide. Nous travaillerons ici sur les lettres ASCII A, C, G et T.

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

## Reconnaître un début connu (3 min)

Dans une expression, `<>` assemble des chaînes. Dans un motif, il permet
de reconnaître un préfixe connu et de capturer le reste. Prévoyez le résultat.

```elixir
"salut " <> name = "salut Ada"
{name, "Bonjour " <> name}
```

Le préfixe de notre motif est une chaîne écrite dans le code, ici `"salut "`.
Nous ne pouvons pas écrire `first <> rest` pour deviner deux morceaux de
longueur inconnue. En revanche, le préfixe connu peut contenir plusieurs
caractères. Le nom `rest` capturera ce qui suit, même une chaîne vide.

## Compter les A (6 min)

Nous recevons uniquement les lettres majuscules `A`, `C`, `G`, `T`.
Le contrat de `DNA.count_a/2` ressemble au comptage de listes : le deuxième
paramètre contient le nombre de A déjà vus, ajouté à sa valeur initiale.
La chaîne vide termine le calcul et renvoie ce total.

Écrivez quatre clauses avec un préfixe littéral : `"A" <> rest`, puis les
trois autres lettres. Chaque clause consomme une lettre. Pour `A`, le
prochain appel reçoit le compteur augmenté ; pour les autres, il le conserve.
L'appel récursif doit être la dernière opération de chaque clause.

```elixir
defmodule DNA do
  def count_a("", total), do: total
  # Écrivez les clauses des quatre préfixes, sans rappeler sur le texte entier.
end
```

Ces exemples au format doctest décrivent des entrées et leurs résultats.
Dans Livebook, nous les exécutons avec les assertions de la cellule suivante.

```text
iex> DNA.count_a("ACA", 0)
2

iex> DNA.count_a("CGT", 5)
5
```

```elixir
assert DNA.count_a("", 0) == 0
assert DNA.count_a("ACGTA", 0) == 2
assert DNA.count_a("CGT", 5) == 5
assert DNA.count_a("AA", 3) == 5
```

## Se préparer à lire un langage (3 min)

Tracez `DNA.count_a("ACA", 0)` dans une cellule de texte : pour chaque appel,
notez le préfixe reconnu, le reste et le compteur. Puis choisissez un cas
personnel et écrivez une assertion avec le résultat attendu.

Quel souci rencontrerions-nous avec `"AX"` ? L'entrée garantie rend notre
première fonction courte ; un lecteur de langage devra expliquer ce qui
n'a pas pu être lu. Nous retrouverons ce besoin dès AP2.

Pour aller plus loin, écrivez `Symbols.read/1` : `"+" <> rest` donne
`{:plus, rest}`, `"*" <> rest` donne `{:times, rest}`, et tout autre texte
donne `{:error, :unknown_symbol}`. Attention à placer le cas général à la
fin ! Vérifiez notamment `Symbols.read("+ 2.0") == {:plus, " 2.0"}`.

## Garder une trace

Sauvegardez ce notebook dans `entrainement/ap1-chaines.livemd`,
en dehors du dossier collecté `AP1/`. Retrouvez la notion suivante dans
`ap1-05-pile-calculatrice.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).
