INF6120 - Laboratoire 9

Sommaire

Pour ce laboratoire, nous allons utiliser l’exemple interp5.ml

Avant tout :

  • clonez le dépôt d’exemples : git clone https://gitlab.info.uqam.ca/inf6120/exemples
  • exécutez l’exemple interp5 : cd exemples/interpreter ; dune exec ./interp5.exe
  • lisez attentivement le code interp5.ml

Tout le reste du labo se fera à partir du code de interp5.ml. Vous pouvez donc effectuer vos modifications directement dans ce fichier.

Représentation d’un programme

  1. Écrire le programme OCaml qui correspond au code qui est évalué dans l’exemple interp5 (à la dernière ligne du fichier)
  2. Transcrire le code OCaml suivant en représentation sous forme d’AST, et vérifier le résultat avec l’interpréteur interp5 :
let a = 1 in
let b = 2 in
let f = function x -> function y -> x + y in
f a b

Booléens

Ajouter le support des booléens tel que vu au cours.

Ajout de comparaisons

  • Définir les opérateurs < et > qui opèrent sur des nombres. Utiliser un typage fort.
  • Définir l’opérateur = qui compare les types primitifs du langage (booléens, entiers). Utiliser un typage fort.

Nombres réels

Ajouter le support pour des nombres réels (représentés par le type float en OCaml), de façon à ce que :

  • on aie un constructeur Float pour introduire une expression représentant un réel
  • les opérations mathématiques soient supportés sur les flottants avec un typage strict (on ne peut pas additionner un réel avec un entier par exemple)

Typage faible

Modifier le code de l’exercice précédent pour introduire du typage faible sur les nombres : on peut par exemple ajouter un flottant avec un entier.

Afficher une valeur

Ajouter une nouvelle expression Print qui affiche la valeur de l’expression qui lui est passée en argument.

Application partielle

L’interpréteur d’exemple ne permet pas l’application partielle, par exemple (function x y -> x + y) 1 donnera lieu a une TypeError. Dans cet exercice, vous devez adapter le code pour permettre l’évaluation partielle. Cela peut se faire de deux façons :

  • modifier les fonctions pour n’avoir qu’un seul paramètre
  • détecter les cas d’applications partielles lors de l’appel de fonction, et retourner une fermeture plutôt que d’appliquer la fonction

Implémenter les deux solutions, une à la fois.

Liaison dynamique

Ceci est un exercice bonus avancé.

Une approche alternative pour la gestion des environnements lors de l’appel de fonction est ce qu’on appelle la liaison dynamique (dynamic binding ou dynamic scoping). Dans cette approche, plutôt que d’étendre l’environnement de définition de la fermeture, c’est l’environnement d’appel qui est étendu.

Par exemple, avec cette approche, la liaison a sera évaluée à 5 plutôt que 3 dans la fonction p du programme suivant :

let a = 3 in
let p = fun x -> x - a in
a := 5;
p 2

Gestion des erreurs

Ceci est un exercice bonus avancé.

Enlever le type d’exception TypeError de l’interpréteur. Adapter le type de retour de eval pour retourner une valeur optionnel : soit l’évaluation réussi et on récupère une valeur, soit l’évaluation échoue et on récupère une erreur (par exemple, représentée par None). Adapter ensuite les définitions pour que le code compile et s’exécute.

La fonction (monadique) Option.bind peut s’avérer utile pour éviter d’avoir trop de match imbriqués.