Programmation fonctionnelle — Théophile Bastian =============================================== Ce projet implémente les deux fonctionnalités de cœur demandées dans le sujet, à savoir * compiler avec succès le langage de base (transformation CPS + défonctionalisation) ; * ajouter une primitive ifzero. Quelques fonctionnalités supplémentaires ont été implémentées, et sont détaillées plus bas. Le dépôt Git du projet se situe ici : >> https://git.tobast.fr/tobast/mpri-funcprog-project/ << **ATTENTION !** `src/tests/` est un git-submodule, il est donc nécessaire de cloner avec le flag `--recursive`, ou de lancer ensuite un git submodule update --init afin de pouvoir récupérer le dépôt entier ! Flags disponibles pour `joujou` ------------------------------- En plus de `--debug`, quelques flags ont été ajoutés : * `--light-debug` : affiche uniquement les langages intermédiaires pretty-printés pour la lisibilité et non l'exhaustivité. Voir plus bas. * `--no-var-var-bind` : désactive la passe de suppression des liaisons variable-variable. Voir plus bas. * `--no-const-propagation` : désactive la passe de propagation naïve des constantes. Voir plus bas. Fichiers de tests ----------------- Tous les tests fournis, ainsi que ceux ajoutés, donnent le bon résultat (incluant `loop`, sur lequel `gcc` fonctionne). La plupart des tests sont de moi, mais certains sont de Glen Mével, partagés via le dépôt https://github.com/tobast/mpri18-funcprog-tests * `if_fib.lambda` (par Glen) : fibonacci avec ifzero * `if_func.lambda` : tester ifzero en se basant sur `church.lambda` * `if_func_branch.lambda` : tester la branche prise par ifzero * `if_nested.lambda` (par Glen) : constructions ifzero imbriquées * `multi_args.lambda` : fonction à deux arguments * `multi_args_rec.lambda` : fonction récursive à plusieurs arguments * `over_application.lambda` : fonction sur-appliquée (`id id x`) * `partial_eval.lambda` : évaluation partielle de fonction * `rec_factorial.lambda` : récursion simple (factorielle) * `rec_fibo.lambda` : récursion plus compliquée (fibonacci) * `redef.lambda` : redéfinition d'une variable avec le même nom * `ren.lambda` (par Glen) : transitivité de l'effacement des var-var * `simple_call.lambda` : appel de fonction simple * `simple_if.lambda` : construction ifzero simple Transformation CPS ------------------ La transformation CPS suit essentiellement les lignes directrices du projet. Une attention particulière a été portée à essayer de générer le **moins de continuations inutiles possible**. Par exemple, naïvement, le code `id y` serait traduit en quelque chose comme cps_transf y (λx · cps_transf id (λf · f x k)) ce qui donnerait let xCont x = let fCont f = Call f x k in Call fCont id in Call xCont y Le code généré par ce projet serait plutôt de la forme let f = id in let x = y in Call f x cont ce qui est optimisé avant le passage au C en un simple Call id y cont Défonctionalisation ------------------- Rien de particulier à signaler sur cette partie, suit les lignes directrices du projet. Élimination des associations variable = variable ------------------------------------------------ Comme suggéré, une passe de compilation après `Defun`, implémentée dans le module `VarVarBind`, se charge de supprimer toutes les instructions du type let x = y in (* … *) en remplaçant simplement `y` par `x` dans la suite, lorsque x et y sont des variables. Il suffit pour cela d'un parcours du code, utilisant un environnement mappant certaines variables sur certaines autres. On prend soin de respecter la transitivité, c'est-à-dire de traduire correctement let y = x in let z = y in (* … *) Propagation naïve des constantes -------------------------------- Pour nettoyer un peu plus le code produit, le module `ConstantPropag` effectue après le passage de `VarVarBind` une sorte de propagation naïve des constantes, c'est-à-dire qu'on propage les constantes et simplifie les expressions autant que possible, sans toutefois jamais propager au-delà d'un appel de fonction. La propagation au-delà d'un appel de fonction (non implémentée, donc), plus compliquée à implémenter, aurait toutefois pu supprimer des continuations inutiles du type de celles mentionnées pour CPS plus haut. Pretty-printing --------------- Pour m'aider à y voir clair tout au long du projet, j'ai implémenté des pretty printers n'affichant rien de superflu pour `Tail` et `Top`. Par exemple, sur le test `simple_call.lambda`, la sortie pour `Tail` est let bl_exit1_ = λ((v_7_)) · Exit in let id = λ((x) (bl_6_)) · Call bl_6_ (x) in let bl_3_ = λ((v_2_)) · Print v_2_; Call bl_exit1_ (v_2_) in let v_4_ = 42 in let v_5_ = id in Call v_5_ (v_4_) (bl_3_) On peut obtenir la sortie des pretty-printers avec `--debug`, ou avec `--light-debug` pour n'avoir que ces sorties là.