Accumulation de valeurs

Comme la plupart des expressions Common Lisp, loop renvoie une valeur. Par défaut, cette valeur est nil, mais il est possible de la modifier.

La façon habituelle de modifier cette valeur de retour est d'employer une clause d'accumulation de valeurs. Deux types de clauses d'accumulation existent : l'accumulation dans une liste et l'accumulation arithmétique.

Pour l'accumulation dans une liste, une clause parmi les clauses collect, append et nconc peut être utilisée (les mots-clés collecting, appending et nconcing peuvent être employés à la place de collect, append et nconc respectivement). La clause collect accumule les valeurs données dans une liste qui est renvoyée à la fin de la boucle. La clause append accumule des listes dont la concaténation (non destructive) est renvoyée à la fin de la boucle. La clause nconc est similaire à append, sauf que la concaténation est destructive. Exemples :

* (loop for s = "hello" then (subseq (reverse s) 1)
        repeat 3
        collect s)

("hello" "lleh" "ell")
* (loop for elem on '(a 233 "hello" #$\backslash$ A) by #'cddr
        collect elem)

((A 233 "hello" #$\backslash$ A) ("hello" #$\backslash$ A))
* (loop for elem on '(a 233 "hello" #$\backslash$ A) by #'cddr
        append elem)

(A 233 "hello" #$\backslash$ A "hello" #$\backslash$ A)
*

Pour l'accumulation arithmétique, l'une des clauses count, maximize, minimize et sum doit être employée (les mots-clés counting, maximizing, minimizing et summing peuvent être utilisés à la place de count, maximize, minimize et sum respectivement). La clause count compte le nombre de fois que l'évaluation de son argument donne vrai. La clause maximize garde la valeur maximale de toutes les évaluations de son argument. La clause minimize est similaire à la clause maximize sauf que c'est la valeur minimale qui est retenue. La clause sum accumule la somme de l'évaluation de ses arguments. Exemples :

* (loop for i from 4 to 8
        count (oddp i))

2
* (loop for i from 4 to 8
        count (evenp i))

3
* (loop for i in '(6 3 4 7 4 9 5)
        maximize i)

9
* (loop for i in '(6 3 4 7 4 9 5)
        maximize (sin i))

0.6569866
* (loop for i in '(6 3 4 7 4 9 5)
        minimize (sin i))

-0.9589243
* (loop for i in '(6 3 4 7 4 9 5)
        sum (* i i))

232
*

Avec ce type d'utilisation, au plus une de ces clauses est utilisable dans une boucle car une seule variable est utilisée pour l'accumulation (certaines combinaisons sont possibles, mais rarement utilisées). Le mot-clé into permet de donner le nom d'une variable à utiliser pour l'accumulation, permettant ainsi l'utilisation de plusieurs clauses d'accumulation. Dans ce cas, les variables explicites sont souvent utilisées dans la clause finally. Exemple :

* (loop for i from 7 to 40 by 10
        sum i into total
        collect i
        finally (format t "total: ~a~%" total))
total: 88
(7 17 27 37)
*

Irene DURAND
2011-10-14