Parenthesons.

This commit is contained in:
Julien Palard 2022-04-14 23:25:04 +02:00
parent 89b8ac0e75
commit 334241f26a
1 changed files with 215 additions and 0 deletions

View File

@ -0,0 +1,215 @@
status: hidden
title: Python — Parenthésons
slug: eiRah1ch-parenthesons
robots: noindex
# Partie
Après Epitech Digital, et un doctorat en informatique vous rejoignez
une equipe chargée de concevoir le prochain langage de programmation à
la mode : le Morecambe.
Dans lequipe « ASV », « Age^WAnalyse Syntaxique et Validation », vous
travaillez sur le parenthésage des expressions :
- `(a + b)` est valide.
- `)a + b(` nest pas valide.
- `(a + (b + c))` est valide.
- `(a + (b + c)` nest pas valide.
- `a * (b + c) + (d / 2)` est valide…
Jusque-là ça va, mais Morecambe est un langage moderne, il ne sarrête
pas aux mathématiques classiques, et permet dexprimer de la logique
combinatoire, du lambda-calcul, de la sémantique dénotationnelle (en
convergence et en divergence), et jen passe, ainsi :
- `(λa ∘ λb)(3)` est valide, cest une simple composition des
fonctions `a` et `b`, immédiatement appellée.
- `⍼((a∘b)(3))|⍼((c∘d)(12))` est valide, cest le « Right Angle with
Downwards ZigZag Arrow » qui permet la dénotation (divergente, pour
le coup), le `|` ne servant quà chaîner, comme en bash,
naturellement.
- `[¬(a ⋀ b) ¬(c ⋀ d)] ∀ a⍼((c∘d)(12)` nest cependant **PAS**
valide, bien qu[Augustus De
Morgan](https://fr.wikipedia.org/wiki/Lois_de_De_Morgan) aurait pu
la corriger en un coup de cuiller à pot.
Votre première tâche sera donc décrire une fonction, en Python (il
faudra la réecrire en Morecambe une fois le compilateur Morecambe
fonctionnel, pour compiler Morecambe en Morecambe et boucler la
boucle, en attendant, on code en Python). Une fonction nommée
`is_correctly_balanced` qui prend en paramètre une chaîne de
caractères nommée `expression`, et qui renvoie `True` si lexpression
est correctement paremthéséee, et `False` dans le cas
contraire.
Léquipe vous a préparé quelques tests unitaires et vous aurez la
bienveillance de les stocker dans le projet afin de pouvoir les
exécuter avec `pytest` :
```python
def test_bare():
assert is_correctly_balanced("") is True
assert is_correctly_balanced("()") is True
assert is_correctly_balanced("(((())))") is True
assert is_correctly_balanced("()()()()") is True
assert is_correctly_balanced("()(())()") is True
assert is_correctly_balanced(")(") is False
assert is_correctly_balanced("(((") is False
assert is_correctly_balanced("((()") is False
assert is_correctly_balanced("()))") is False
assert is_correctly_balanced("()()()(") is False
def test_full():
assert is_correctly_balanced("(a + b)")
assert not is_correctly_balanced(")a + b(")
assert is_correctly_balanced("(a + (b + c))")
assert not is_correctly_balanced("(a + (b + c)")
assert is_correctly_balanced("a * (b + c) + (d / 2)")
assert is_correctly_balanced("(λa ∘ λb)(3)")
assert is_correctly_balanced("⍼((a∘b)(3))|⍼((c∘d)(12))")
assert not is_correctly_balanced("[¬(a ⋀ b) ¬(c ⋀ d)] ∀ a⍼((c∘d)(12)")
```
Dites, à quel point cest frustrant si je vous dis que `((()))` écrit
à lenvers çax donne `)))(((` ?
# Partie Ⅱ
En rédigant votre fonction vous remarquez un fait amusant : donné un
certain nombre de paires de parenthéses, il ny a quun nombre fini de
possibilités pour les agencer.
Vous ne pouvez donc vous retenir dimplementer une fonction pour tous les
lister !
Votre fonction doit sappeler `gen_correctly_balanced_expressions` et
prendre un seul parametre `n` : le nombre de paires de
parenthéses.
Elle doit renvoyer un iterable de tous les parenthésages possibles,
chaque parenthésage étant exprimé sous la forme dune chaine de
caractères. Vous devinerez vite quil nexiste quune seule manière de
parenthéser une seule paire de parenthéses, puis vous découvrirez
quil existe
- deux manieres de parenthéser deux paires,
- 5 manieres den parenthéser trois,
- 14 den parenthéser 4,
- ...
- 4862 den parenthéser 9...
Voici par exemple les 14 parenthésages valides avec quatres paires de
parenthéses :
- `(((())))`
- `((()()))`
- `(()(()))`
- `(()()())`
- `((())())`
- `()((()))`
- `()(()())`
- `()()(())`
- `()()()()`
- `()(())()`
- `(())(())`
- `(())()()`
- `((()))()`
- `(()())()`
Vous utiliserez cette fonction pour tester votre première fonction
avec pytest, prouvant sa robustesse, et impressionant de fait votre
équipe.
# Partie Ⅲ
Il est maintenant tard, mais vous narrivez pas à décrocher de vos
parenthésages. Vous contemplez votre travail, vous jouez avec
`gen_correctly_balanced_expressions(5)`,
`gen_correctly_balanced_expressions(6)`… vous nêtes plus très
productif à cette heure de la nuit, mais ces fonctions vous
distraient. Vous vous dites que ça pourraît être joli si on pouvait
remplacer les parenthéses par dautres symboles…
Vous ajoutez donc deux arguments optionnels à votre fonction :
`opening`, et `closing`, qui respectivement valent par defaut `"("`,
et `")"` afin de ne pas changer le comportement dorigine de votre
fonction.
Et vous voilà parti à jouer avec votre nouvelle fonction :
- `gen_correctly_balanced_expressions(4, "[", "]")`
- `gen_correctly_balanced_expressions(4, "<", ">")`
- `gen_correctly_balanced_expressions(4, "la", "li")`
- `gen_correctly_balanced_expressions(4, "Tum ", "Pak ")`
- `gen_correctly_balanced_expressions(4, "𝅗𝅥", "𝅘𝅥𝅮")`
- `gen_correctly_balanced_expressions(4, "Je suis en retard…", "en retard…")`
# Partie Ⅳ
Il est vraiment tard cette fois, mais vous décidez de suivre le lapin
blanc jusquau fond du terrier.
Et ça y est, vous testez enfin :
`gen_correctly_balanced_expressions(5, "1", "0")`
Du binaire… des nombres ! Et aucun ne commence par zéro !! Et ils
sont tous pairs ! Ça ne peut pas être une coïncidence…
Vous rédigez alors une fonction `gen_balanced_sequence` qui prend en
paramètre `n`, le nombre de pairs de bits à utiliser, et qui renvoie
un iterable de nombres entiers ordonnés par ordre croissant : les
nombres genérés par votre expérience précédente. Ces séquences sont
interessantes, mais trop courtes :
```text
2
```
puis :
```text
10
12
```
puis :
```text
42
44
50
52
56
```
Vous décidez alors de rédiger une fonction `gen_balanced_sequences`
(notez le pluriel) qui ne prend pas de paramètre, mais qui renvoie un
itérable infini (ou qui affiche et ne renvoie rien, à votre guise), des nombres
genérés par la fonction précédente, vous obtenez alors :
```text
2
10
12
42
44
50
52
56
170
172
```
Vous contemplez la séquence ainsi générée, et vous hésitez entre aller
dormir et vous lancer dans une thèse pour étudier cette séquence…