Définition de fonctions globales

La grande majorité des fonctions sont globales. Une telle fonction est accessible à partir de son nom partout dans un programme.

Comme pour une variable spéciale, le nom d'une fonction globale est un symbole. Le même symbole peut être utilisé pour nommer une fonction et une variable spéciale. On parle d'espaces de noms. Common Lisp a (au moins) deux espaces de noms différents : l'espace des noms de variables et l'espace des noms de fonctions. Il est donc relativement courant de voir des constructions comme celle-ci (de McCLIM) :

(defmethod graft ((graft graft))
  graft)

Pour définir une fonction globale, on utilise le plus souvent la macro defun. La syntaxe générale de defun est :

(defun nom lambda-liste
  expression-1
  ...
  expression-n)

nom est le nom de la fonction et lambda-liste la liste des paramètres de la fonction, traitée en détail dans la section 7.2. Le corps de la fonction, à savoir la suite d'expressions, constitue un progn implicite (voir chapitre 10). La valeur de expression-n sera la valeur de l'appel à la fonction. La suite d'expressions qui précède, si elle existe, devrait donc toujours avoir des effets de bords. Exemple :

* (defparameter *count* 0)

*COUNT*
* (defun next ()
    (incf *count*)
    (1- *count*))

NEXT
* (next)

0
* (next)

1
*

Dans cet exemple, la liste des paramètres est vide. La première expression du corps incrémente la variable spéciale *count* et la deuxième (et dernière) expression renvoie cette valeur moins 1. Cet exemple est un peu artificiel, car on aura plutôt tendance à l'écrire comme ceci :

* (defparameter *count* 0)

*COUNT*
* (defun next ()
    (prog1 *count* (incf *count*)))

NEXT
* (next)

0
* (next)

1
*

voire :

* (defparameter *count* -1)

*COUNT*
* (defun next ()
    (incf *count*))

NEXT
* (next)

0
* (next)

1
*

La définition avec defun peut être imbriquée dans d'autres expressions. Dans ce cas, ce n'est pas une fonction locale qui est définie, mais une fonction globale avec éventuellement une partie de l'environnement close (voir Annexe B) ; on parle de fermeture :

* (let ((count -1))
    (defun next ()
      (incf count)))
Converted NEXT.

NEXT
* (next)

0
* (next)

1
*

Le message ``Converted NEXT.'' vient du compilateur CMUCL. Dans cet exemple, la variable lexicale count est enfermée dans le contexte où la fonction next est définie. Il est impossible de la modifier sans passer par la fonction next.

La macro defun modifie l'association entre un symbole et une fonction. Cette association est accessible au programmeur par le biais de symbol-function :

* (let ((count -1))
    (defun next ()
      (incf count)))
Converted NEXT.

NEXT
* (eq #'next (symbol-function 'next))

T
* (setf (symbol-function 'next) #'+)

#<Function + 102671B9>
* (next 10 4)

14
*

Cette possibilité est utilisée par exemple par l'outil de mise au point et par le traceur afin d'entourer une fonction d'un prologue et d'un épilogue.

Irene DURAND
2011-10-14