mdk.fr/content/pages/parenthesons.md

6.6 KiB
Raw Blame History

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 quAugustus 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 :

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 :

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…