status: hidden title: Python — Parenthésons slug: eiRah1ch-parenthesons robots: noindex # Partie Ⅰ Après Epitech Digital, et un doctorat en informatique vous rejoignez une équipe 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ée, 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 ça 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 toutes 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 manières de parenthéser deux paires, - 5 manières 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 paires 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…