6.6 KiB
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 fonctionsa
etb
, 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 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
:
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 :
2
puis :
10
12
puis :
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 :
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…