Parenthesons.
This commit is contained in:
parent
89b8ac0e75
commit
334241f26a
|
@ -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 l’equipe « ASV », « Age^WAnalyse Syntaxique et Validation », vous
|
||||
travaillez sur le parenthésage des expressions :
|
||||
|
||||
- `(a + b)` est valide.
|
||||
- `)a + b(` n’est pas valide.
|
||||
- `(a + (b + c))` est valide.
|
||||
- `(a + (b + c)` n’est pas valide.
|
||||
- `a * (b + c) + (d / 2)` est valide…
|
||||
|
||||
Jusque-là ça va, mais Morecambe est un langage moderne, il ne s’arrête
|
||||
pas aux mathématiques classiques, et permet d’exprimer de la logique
|
||||
combinatoire, du lambda-calcul, de la sémantique dénotationnelle (en
|
||||
convergence et en divergence), et j’en passe, ainsi :
|
||||
|
||||
- `(λa ∘ λb)(3)` est valide, c’est une simple composition des
|
||||
fonctions `a` et `b`, immédiatement appellée.
|
||||
- `⍼((a∘b)(3))|⍼((c∘d)(12))` est valide, c’est 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)` n’est 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 l’expression
|
||||
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 c’est frustrant si je vous dis que `((()))` écrit
|
||||
à l’envers çax donne `)))(((` ?
|
||||
|
||||
|
||||
# Partie Ⅱ
|
||||
|
||||
En rédigant votre fonction vous remarquez un fait amusant : donné un
|
||||
certain nombre de paires de parenthéses, il n’y a qu’un nombre fini de
|
||||
possibilités pour les agencer.
|
||||
|
||||
Vous ne pouvez donc vous retenir d’implementer une fonction pour tous les
|
||||
lister !
|
||||
|
||||
Votre fonction doit s’appeler `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 d’une chaine de
|
||||
caractères. Vous devinerez vite qu’il n’existe qu’une seule manière de
|
||||
parenthéser une seule paire de parenthéses, puis vous découvrirez
|
||||
qu’il existe
|
||||
- deux manieres de parenthéser deux paires,
|
||||
- 5 manieres d’en parenthéser trois,
|
||||
- 14 d’en parenthéser 4,
|
||||
- ...
|
||||
- 4862 d’en 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 n’arrivez 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 d’autres 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 d’origine 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 jusqu’au 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…
|
Loading…
Reference in New Issue