Les deux opérateurs spéciaux, flet et labels permettent de créer des fonctions locales à savoir des fonctions dont le nom est connu dans un contexte restreint. Les deux ont une syntaxe similaire à celle de let (voir chapitre 10) :
(flet (fn-1
...
fn-m)
expr-1
...
expr-n)
et
(labels (fn-1
...
fn-m)
expr-1
...
expr-n)
Chaque fn-i est une fonction locale avec
la syntaxe suivante :
(nom lambda-liste
corpsexp-1
...
corpsexp-k)
et fonctionne comme une définition de fonction globale. Parmi les expr-i il y aura toujours au moins un appel à l'une des fonctions locales. Exemple :
* (flet ((square (x) (* x x))
(add3 (x) (+ x 3)))
(square (add3 5)))
64
*
La différence principale entre flet et labels est une question de portée des noms. Pour flet, cette portée ne couvre pas les corpsexp-i, alors que pour labels, c'est le cas. Par conséquent, flet est utile pour redéfinir temporairement des fonctions globales ou pour définir des fonctions qui ne s'appellent pas entre elles, alors que labels est utile pour des définitions mutuellement récursives. Exemples :
* (flet ((+ (&rest l) (print l) (apply #'+ l)))
(+ 2 3 4))
(2 3 4)
9
* (labels ((fact (n) (if (< n 2) 1 (* n (fact (1- n))))))
(fact 40))
815915283247897734345611269596115894272000000000
*
C'est uniquement la liaison entre le nom et la fonction qui est locale. La fonction, comme pratiquement tous les objets Common Lisp, a une durée de vie indéfinie. Exemple :
* (labels ((fact (n) (if (< n 2) 1 (* n (fact (1- n))))))
(setf *fn* #'fact))
#<Interpreted Function FACT 4816B779>
* (funcall *fn* 40)
815915283247897734345611269596115894272000000000
*