common-lisp
Structures de contrôle
Recherche…
Constructions conditionnelles
Dans Common Lisp, if
est la construction conditionnelle la plus simple. Il a la forme (if test then [else])
le then
test
else
(if test then [else])
et est évaluée pour then
si test
est vrai et d' else
autrement. Le reste peut être omis.
(if (> 3 2)
"Three is bigger!"
"Two is bigger!")
;;=> "Three is bigger!"
Une différence très importante entre if
dans Common Lisp et if
dans de nombreux autres langages de programmation, CL est if
une expression, pas une déclaration. En tant que tels, if
formulaires renvoient des valeurs pouvant être affectées à des variables, utilisées dans les listes d'arguments, etc.:
;; Use a different format string depending on the type of x
(format t (if (numberp x)
"~x~%"
"~a~%")
x)
De Common Lisp if
peut être considéré comme équivalent à l' opérateur ternaire: en C # et d' autres langues « accolade ».
Par exemple, l'expression C # suivante:
year == 1990 ? "Hammertime" : "Not Hammertime"
Est équivalent au code Common Lisp suivant, en supposant que cette year
contient un entier:
(if (eql year 1990) "Hammertime" "Not Hammertime")
cond
est une autre construction conditionnelle. Il est quelque peu similaire à une chaîne de déclarations if
et a la forme:
(cond (test-1 consequent-1-1 consequent-2-1 ...)
(test-2)
(test-3 consequent-3-1 ...)
... )
Plus précisément, cond
a zéro ou plusieurs clauses , et chaque clause a un test suivi de zéro ou plusieurs conséquences. L'ensemble de la construction cond
sélectionne la première clause dont le test n'est pas évalué à nil
et évalue ses conséquences dans l'ordre. Il renvoie la valeur de la dernière forme dans les conséquents.
(cond ((> 3 4) "Three is bigger than four!")
((> 3 3) "Three is bigger than three!")
((> 3 2) "Three is bigger than two!")
((> 3 1) "Three is bigger than one!"))
;;=> "Three is bigger than two!"
Pour fournir une clause par défaut à évaluer si aucune autre clause n'équivaut à t
, vous pouvez ajouter une clause qui est vraie par défaut à l'aide de t
. Ce concept est très similaire au concept CASE...ELSE
de SQL, mais il utilise un booléen littéral true plutôt qu'un mot-clé pour accomplir la tâche.
(cond
((= n 1) "N equals 1")
(t "N doesn't equal 1")
)
Une construction if
peut être écrite comme une construction cond
. (if test then else)
et (cond (test then) (t else))
sont équivalents.
Si vous n'avez besoin que d'une clause, utilisez when
ou à unless
:
(when (> 3 4)
"Three is bigger than four.")
;;=> NIL
(when (< 2 5)
"Two is smaller than five.")
;;=> "Two is smaller than five."
(unless (> 3 4)
"Three is bigger than four.")
;;=> "Three is bigger than four."
(unless (< 2 5)
"Two is smaller than five.")
;;=> NIL
La boucle do
La plupart des constructions en boucle et conditionnelles dans Common Lisp sont en fait des macros qui cachent des constructions plus basiques. Par exemple, les dotimes
et dolist
sont construits sur la macro do
. Le formulaire pour do
ressemble à ceci:
(do (varlist)
(endlist)
&body)
-
varlist
est composée des variables définies dans la boucle, de leurs valeurs initiales et de leur modification après chaque itération. La partie 'change' est évaluée à la fin de la boucle. -
endlist
contient les conditions de fin et les valeurs renvoyées à la fin de la boucle. La condition de fin est évaluée au début de la boucle.
En voici un qui commence à 0 et va jusqu'à (non compris) 10.
;;same as (dotimes (i 10))
(do (( i (+ 1 i))
((< i 10) i)
(print i))
Et en voici un qui se déplace dans une liste:
;;same as (dolist (item given-list)
(do ((item (car given-list))
(temp list (cdr temp))
(print item))
La partie varlist
est similaire à celle d'une instruction let
. Vous pouvez lier plusieurs variables et elles n'existent que dans la boucle. Chaque variable déclarée est dans son propre ensemble de parenthèses. En voici un qui compte combien de 1 et 2 sont dans une liste.
(let ((vars (list 1 2 3 2 2 1)))
(do ((ones 0)
(twos 0)
(temp vars (cdr temp)))
((not temp) (list ones twos))
(when (= (car temp) 1)
(setf ones (+ 1 ones)))
(when (= (car temp) 2)
(setf twos (+ 1 twos)))))
-> (2 3)
Et si une macro de boucle while n'a pas été implémentée:
(do ()
(t)
(when task-done
(break)))
Pour les applications les plus courantes, les macros dotimes
et doloop
plus spécifiques sont beaucoup plus succinctes.