Back to Explore

Prog comp - Cours 4 - Notes de cours et TD Summary & Study Notes

These study notes provide a concise summary of Prog comp - Cours 4 - Notes de cours et TD, covering key concepts, definitions, and examples to help you review quickly and study effectively.

1.4k words2 views
Notes

📄 Cours principal — Polymorphisme, ordres supĂ©rieurs et infĂ©rence (cours-4_ok.pdf)

But et contexte Courte vue d'ensemble : le document explique le polymorphisme paramĂ©trique (OCaml, Java gĂ©nĂ©riques), les ordres supĂ©rieurs (fonctions comme valeurs) et l'infĂ©rence de types (Damas–Hindley–Milner) avec ses algorithmes d'unification et de gĂ©nĂ©ralisation.

📚 Polymorphisme : notions clĂ©s

Polymorphisme paramétrique : permet d'écrire un seul code réutilisable pour plusieurs types (ex. type 'a list en OCaml, List en Java). Ici 'a ou T est un paramÚtre de type. Avantages : sécurité statique, réduction des casts, réutilisabilité.

Polymorphisme d'inclusion : héritage/implémentation d'interfaces en PO (Java). DiffÚre du polymorphisme paramétrique.

Compilation et modularité : certains langages compilent une seule instance générique (OCaml/Java), d'autres génÚrent du code pour chaque instanciation (templates C++ / macros C).

🔁 Ordres supĂ©rieurs et fonctions comme valeurs

Les fonctions peuvent ĂȘtre passĂ©es en argument, retournĂ©es, stockĂ©es. Exemples pratiques : map, reduce, iter. En OCaml, ces fonctions sont naturellement polymorphes : map : (’a -> ’b) -> ’a list -> ’b list.

Captures et fermetures : une fonction garde accĂšs Ă  l'environnement lexical oĂč elle a Ă©tĂ© dĂ©finie ; la reprĂ©sentation d'une fonction Ă  l'exĂ©cution est une fermeture (pointeur code + valeurs capturĂ©es). En Java/Python, on simule souvent une fermeture via un objet avec Ă©tat.

🧠 InfĂ©rence de types (Damas–Hindley–Milner)

Objectif : inférer automatiquement les types sans annotations explicites. On distingue deux phases :

  • gĂ©nĂ©ration de contraintes (variables de type TVar pour inconnues),
  • rĂ©solution par unification (mise Ă  jour d'une solution mutable sol : TVar -> type).

Types de base dans l'algorithme : int, t1 -> t2, variables de type TVar; plus tard on introduit paramÚtres de type (TParam, notés 'a) pour le polymorphisme.

Algorithme de typage (rĂšgles importantes) :

  • n (entier) -> type int
  • var -> env(var)
  • fun v -> e : crĂ©er t1 = fresh(); typer e avec env[v -> t1] et rĂ©sultat t1 -> t2
  • (e1 e2) : t1 = type(e1), t2 = type(e2), t3 = fresh(); ajouter contrainte t1 = t2 -> t3, retourner t3
  • let v = e1 in e2 : typer e1, gĂ©nĂ©raliser si nĂ©cessaire, ajouter au env pour e2
  • if e1 = 0 then e2 else e3 : contraindre e1 : int et t2 = t3

⚙ Unification et utilitaires

Fonctions-clés : apply(t, sol) (applique les substitutions connues dans sol), subst(t, v, u) (remplace occurrences de v par u), occurs(v, t) (évite les cycles), add(sol, t1, t2) (ajoute contrainte et met à jour sol). L'algorithme garantit que sol n'a pas de variables résolues contenant d'autres variables résolues (aprÚs apply/subst).

🔁 Polymorphisme let (gen/inst)

Pour autoriser le polymorphisme, distinguer variables de type résolues (TVar) et paramÚtres de type (TParam, ex. 'a). Deux opérations :

  • gen(t) : gĂ©nĂ©ralise un type en remplaçant les TVar non rĂ©solues par des TParam ('a, 'b...).
  • inst(t) : instancie un type polymorphe en remplaçant ses TParam par TVar fraĂźches.

RÚgle importante : ne généraliser que les types complÚtement résolus (aprÚs apply(sol, t)) pour éviter de généraliser des variables qui auront ultérieurement une solution.

đŸ§© Extensions et prĂ©cautions

  • Paires polymorphes : ajouter type t × t et gĂ©rer inst/gen pour pair, fst, snd.
  • RĂ©fĂ©rences/mutabilitĂ© : la gĂ©nĂ©ralisation auto pour des rĂ©fĂ©rences est dangereuse (exposĂ© via 'weak' en OCaml). Certaines limitations existent en pratique (rĂ©fĂ©rences, recursivitĂ©, modules).

✅ Exemples pratiques et comparaisons

Comparaison OCaml vs Java vs Python pour fonctions/ordres supérieurs :

  • OCaml : rĂ©cursion et listes immuables, infĂ©rence riche.
  • Java : interfaces fonctionnelles, lambdas et gĂ©nĂ©riques, effacement des types Ă  la compilation.
  • Python : valeurs polymorphes sans vĂ©rification statique, style plus impĂ©ratif et comprĂ©hensions.

Conseil d'étude : jouer les exemples (map, reduce, iter), suivre l'algorithme d'inférence sur des petits programmes et vérifier l'évolution de sol lors de l'unification.

📝 Travaux dirigĂ©s — Exercices et tĂąches (TD4-etu.pdf)

Objectifs du TD Pratiquer les fonctions d'ordre supérieur, le polymorphisme, et implémenter l'inférence de types (monomorphe puis polymorphe) selon les étapes vues en cours.

🔧 Exercice 1 — Listes et ordres supĂ©rieurs

TĂąches principales :

  • ImplĂ©menter en OCaml une fonction sum pour sommer une liste d'entiers (type attendu : int list -> int).
  • ImplĂ©menter reduce (fold_left) terminal, puis montrer comment sum est une application partielle de reduce.
  • ImplĂ©menter map_reduce (appliquer f Ă  chaque Ă©lĂ©ment puis rĂ©duire). DĂ©finir compose et dĂ©river map_reduce Ă  l'aide de compose, map et reduce.
  • Donner les types de map, reduce, compose, map_reduce.
  • ImplĂ©mentations Ă©quivalentes en Java (List, Function<T,U>, BiFunction) et versions optionnelles en Java/Python (lambda, functools.reduce) et une version sans liste intermĂ©diaire.

Indices techniques : utiliser l'application partielle en OCaml, boucles for-each en Java, lambda et functools.reduce en Python. Pour la version sans liste intermédiaire, faire une réduction accumulant la transformation.

🔐 Exercice 2 — ReprĂ©sentation des fermetures

Analyse du code OCaml : définir le type de app_ml = app ml, montrer le comportement de app_ml 5 ;; app_ml 10 ;;. Représenter graphiquement les fermetures pour des fonctions qui capturent un état mutable (ex. compteur c = {contents = 0}), préciser l'environnement capturé par next et reset (références vers c.contents partagées ou distinctes selon mk_counter).

🔁 Exercice 3 — Continutations

Programme mystere utilisant continuation explicite : comprendre la trace d'exécution de mystere [2;3;4], expliquer le rÎle de k (accumulateur de continuation), puis réécrire l'algorithme en style direct (sans continuation explicite). Ce TD illustre comment les continuations transforment la structure du calcul (accumulation de fonctions de suite).

đŸ§© Exercice 4 — InfĂ©rence de types (gros projet)

Étapes demandĂ©es :

  1. Définir structures de données pour type et expr, et un env mutable Var -> type.
  2. Implémenter fresh(): unit -> string (compteur global de TVar fraßches) et fonctions d'affichage.
  3. Implémenter occurs(v, t), subst(t, v, u) et apply(t, sol).
  4. Implémenter add(sol, t, u) : algorithme d'unification qui met à jour sol en place, signale une erreur si impossible.
  5. Cas de test pour unification (construites et non satisfaisables). Réinitialiser sol avant chaque test.
  6. Implémenter la fonction type (typprog) : parcours récursif des expressions, génération des contraintes, utilisation d'add et apply. Gérer environment des variables d'expression et la table de solutions.
  7. Étendre au polymorphisme : ajouter TParam, implĂ©menter gen (gĂ©nĂ©ralisation) et inst (instanciation), mettre Ă  jour typprog pour gĂ©nĂ©raliser sur let et instancier lors d'accĂšs aux variables.
  8. Tests : programmes corrects, erreurs de type, fonctions récursives et d'ordre supérieur.
  9. Extension optionnelle : support des paires polymorphes ou autre constructeur choisi.

Conseils pratiques : commencer par l'inférence monomorphe, bien tester apply/subst/occurs/add séparément avant d'attaquer typprog. Lors de la généralisation, appeler apply(sol, t) pour s'assurer que seules les TVar non résolues deviennent des paramÚtres.

📂 DĂ©ploiement et rendu

Indication : l'exercice 4 doit ĂȘtre rendu sur le GitLab dĂ©diĂ© (faire un fork du projet TME4 et pousser les contributions).

đŸ—’ïž Note utilisateur — Contexte et conseils d'utilisation (text:user-input)

Contexte fourni : le document principal est le cours (cours-4_ok.pdf) et les exercices associés sont dans TD4-etu.pdf. Cette note récapitule l'ordre recommandé d'étude et les points d'attention.

🧭 Ordre recommandĂ© d'Ă©tude

  1. Lire rapidement le cours pour comprendre les concepts : polymorphisme, ordres supĂ©rieurs, fermetures et l'algorithme Damas–Hindley–Milner.
  2. Travailler les exercices pratiques du TD dans l'ordre (listes & reduce → fermetures → continuations → infĂ©rence). Cela aide Ă  consolider les aspects thĂ©oriques.
  3. Pour l'inférence : implémenter d'abord les utilitaires (fresh, occurs, subst, apply), tester-les isolément, puis implémenter add (unification) et enfin la fonction de typage récursive.

✅ Points d'attention

  • Toujours appliquer apply(sol, t) avant de gĂ©nĂ©raliser pour Ă©viter de gĂ©nĂ©raliser des variables dĂ©jĂ  rĂ©solues.
  • VĂ©rifier occurs pour Ă©viter lier une TVar Ă  un type qui la contient (cycle).
  • Tester des cas d'erreur (contradiction d'unification) pour s'assurer que add signale correctement l'Ă©chec.
  • Pour les fermetures, bien distinguer valeurs copiĂ©es (immuables) et rĂ©fĂ©rences partagĂ©es (mutables) lors de la reprĂ©sentation graphique.

💡 Astuces pratiques

  • En OCaml, exploiter le pattern matching pour implĂ©menter proprement le typage rĂ©cursif et la traversĂ©e d'expressions.
  • En Java, utiliser java.util.function et List pour les versions gĂ©nĂ©riques des exercices fonctionnels.
  • En Python, functools.reduce et lambdas pour des prototypes rapides.

Bonne étude : lisez le cours, codez les petits exemples, puis attaquez l'inférence étape par étape.

Sign up to read the full notes

It's free — no credit card required

Already have an account?

Create your own study notes

Turn your PDFs, lectures, and materials into summarized notes with AI. Study smarter, not harder.

Get Started Free
Prog comp - Cours 4 - Notes de cours et TD Study Notes | Cramberry