TD de LISP numéro 3 et 4


  1. Paramètres optionnels et APPLY



  2. fonctions d'arité variable et APPLY

  3. Fonctions destructives sur les listes

  4. Définir les différentes fonctions sur les listes en mode destructif (ou modification physique) et non pas en mode copie comme on l'a vu jusqu'ici.

    Fonctions concernées :


  5. Fonctions de partage sur les listes

  6. Entre la copie et la destruction, il y a le partage, qui consiste à ne rien détruire mais à ne recopier que le minimum.
    Définir les fonctions subst et remove en mode partage, de telle sorte que la fonction retourne son argument dans le cas où aucune substitution n'est faite.
    NB. la fonction ne doit effectuer qu'un unique parcours de l'arbre, comme pour les autres versions.

    Une présentation élégante des 3 versions (copie, partage, destruction) de ces fonctions consiste à utiliser un schéma unique dans lequel on ne fait varier que la fonction de construction de liste : typiquement, dans les versions partage et destruction, on remplace l'usage de cons par celui d'une autre fonction, locale.


  7. Calculette

  8. Définir la fonction calcul qui prend une expression arithmétique en paramètre et l'évalue.
    L'expression ne doit contenir que des nombres et des opérateurs arithmétiques usuels.on généralisera ensuite à des opérateurs d'arité quelconque.
    On commencera en ne traitant que des opérateurs binaires et
  9. Les macros
  10. Dans tous les cas, attention aux récursions, aux doubles évaluations et à la capture de variable.
    On utilisera macroexpand pour vérifier la correction des expansions.


  11. Tester backquote

  12. Pour comprendre ce que fait backquote, il est intéressant d'analyser la valeur de `(toto , titi truc ,@tata tutu) ou de toute autre expression backquotée.
    Pour cela, on peut regarder '`(toto , titi truc ,@tata tutu) : comme print restitue la forme bacquotée d'origine, on analysera la valeur en en prenant les car et cdr successifs.
    Expliquer.


  13. Implémenter backquote

  14. L'objectif est de définir le fonctionnement du caractère backquote en définissant une fonction backquotify qui transforme l'expression backquotée en une expression de construction de liste.
    Pour cela, il faut d'abord supposer que ",x" est lu (fonction read) comme la liste (unquote x), de la même manière que "'x" est lu (quote x). Idem pour ",@x" qui est lu (splice-unquote x).
    On procède par étapes
    1. dans un premier temps, on définit backquotify pour qu'il transforme l'expression `(e1 e2 .. en) en (list 'e1 ... 'en) ;
    2. on traite ensuite le cas où des ei sont de la forme (unquote fi) de telle sorte que l'expression produite comporte alors fi à la place de 'ei ;
    3. on généralise alors à un arbre : la récursion ne se fait pas seulement sur le cdr mais aussi sur le car ;
    4. on traite ensuite le cas des (splice-unquote x) : attention, il faut alors faire une récursion de la cellule "du dessus"  (rare contre-exemple à la règle consistant à ne tester dans une récursion que la cellule courante) ;
    5. on finit par la définition d'une fonction de simplification qui fait l'inverse de l'étape 1 en reconstruisant des constantes et qui simplifie les appels imbriqués (append, cons et list* ou list, etc.)
    On peut alors vérifier, que ça marche :

    (bacquotify '((lambda ((unquote (caar args))) (splice-unquote body)) (unquote (cadar args))))
    doit retourner quelque-chose comme :
    (list (list* 'lambda (list (caar args)) body) (cadar args))
    On peut même comparer ce que votre version produit avec le résultat de la version du système, que la question précédente permet d'obtenir.


  15. Récursions terminales et continuations

  16. Une continuation est une fermeture, c'est-à-dire une lambda-expression capturant l'environnement courant, passée en argument à une autre fonction qui appelle la continuation pour se continuer.
    L'un des usages des continuations est de permettre la transformation de n'importe quelle récursion enveloppée en récursion terminale.