Contextes

Un contexte est un bloc avec des variables locales. Il y a deux types de contextes : let et let*. Les deux ont la même syntaxe (à la différence du nom du contexte), mais la sémantique diffère.

Le premier paramètre est une liste de liaisons (en Anglais : bindings) entre variable-valeur. Cette liste est suivie d'un nombre arbitraire d'expressions évaluées comme un progn implicite. Chaque liaison est une liste à deux éléments : la variable et sa valeur. Exemple :

(let ((x 234)
      (y 345))
  (setf *p* (+ x y))
  (* x y))

Ici, deux variables locales, x et y sont créées. La portée de ces deux variables est le corps du let, à savoir les deux expressions (setf *p* (+ x y)) et (* x y). La valeur de la variable x sera 234 et la valeur de la variable y sera 345. Les expressions d'initialisation des variables peuvent être arbitrairement compliquées :

* (let ((x (let ((z *read-base*)) (setf *read-base* 10) (+ z 2)))
        (y (prog1 (car '(1 2 3)) (print "hello"))))
    (+ x y))

"hello"
13
*

Les expressions d'initialisation sont évaluées dans l'ordre syntaxique, mais pour le let, les variables locales sont créées après toutes les initialisations :

* (let ((x 2))
    (let ((x 3)
          (y (+ x 2)))
      (* y x)))

12
*

Dans cet exemple, deux variables portent le nom x. La portée de la première (celle initialisée à 2) couvre toutes les initialisations du let imbriqué. La valeur de l'expression (+ x 2) est donc 4. Par contre, dans le corps du let imbriqué, c'est la variable x initialisée à 3 qui couvre, ce qui explique le résultat.

Il est également possible de remplacer une initialisation de type liste à deux éléments (variable et valeur initiale) par une variable seule. Dans ce cas, la variable est initialisée automatiquement à nil. Le bon style Common Lisp exige que cette valeur implicite ne soit pas utilisée et que la variable soit considérée comme non initialisée. Exemple :

* (let (x
        (y 5))
    (setf x (+ y *read-base*))
    (* x y))

75
*

La seule différence entre le let et le let* est qu'avec let*, les liaisons des variables sont créées séquentiellement après chaque initialisation. Voici par conséquent le résultat de l'exemple ci-dessus avec un let* à la place du let :

* (let ((x 2))
    (let* ((x 3)
           (y (+ x 2)))
      (* y x)))
Warning: Variable X defined but never used.

15
*

Le message de CMUCL indique que la variable x initialisée à 2 n'est jamais utilisée, car toutes les autres occurrences de x font référence à l'autre variable x.

Irene DURAND
2011-10-14