common-lisp
Kontrollstrukturer
Sök…
Villkorliga konstruktioner
I Common Lisp, if
är den enklaste villkorade konstruktionen. Den har formen (if test then [else])
och utvärderas till then
om test
är sant och else
sätt. Den andra delen kan utelämnas.
(if (> 3 2)
"Three is bigger!"
"Two is bigger!")
;;=> "Three is bigger!"
En mycket viktig skillnad mellan if
i Common Lisp och if
i många andra programmeringsspråk är att CL: s if
är ett uttryck, inte ett uttalande. Som sådan, if
formulär returnerar värden, som kan tilldelas variabler, som används i argumentlistor, etc:
;; Use a different format string depending on the type of x
(format t (if (numberp x)
"~x~%"
"~a~%")
x)
Vanliga Lisp if
kan betraktas som likvärdiga med den ternära operatören ?: på C # och andra "lockiga stag" -språk.
Till exempel följande C # -uttryck:
year == 1990 ? "Hammertime" : "Not Hammertime"
Är likvärdigt med följande Common Lisp-kod, förutsatt att year
har ett heltal:
(if (eql year 1990) "Hammertime" "Not Hammertime")
cond
är en annan villkorad konstruktion. Det liknar en kedja av if
uttalanden och har formen:
(cond (test-1 consequent-1-1 consequent-2-1 ...)
(test-2)
(test-3 consequent-3-1 ...)
... )
Mer exakt har cond
noll eller fler klausuler , och varje klausul har ett test följt av noll eller fler följder. Hela cond
konstruktionen väljer den första klausulen vars test inte utvärderar till nil
och utvärderar dess följder i ordning. Det returnerar värdet på den sista formen i följdarna.
(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!"
Om du vill tillhandahålla en standardklausul för att utvärdera om ingen annan klausul utvärderas till t
kan du lägga till en klausul som är sann som standard med t
. Detta är mycket lika i koncept som SQL: s CASE...ELSE
, men det använder en bokstavlig booleska sann snarare än ett nyckelord för att utföra uppgiften.
(cond
((= n 1) "N equals 1")
(t "N doesn't equal 1")
)
En if
konstruktion kan skrivas som en cond
konstruktion. (if test then else)
och (cond (test then) (t else))
är likvärdiga.
Om du bara behöver en klausul, använd when
eller om 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
Do loopen
De flesta looping och villkorade konstruktioner i Common Lisp är faktiskt makroer som döljer bort mer grundläggande konstruktioner. Till exempel dotimes
och dolist
på do
makroen. Formuläret för do
ser ut så här:
(do (varlist)
(endlist)
&body)
-
varlist
består av variablerna definierade i loopen, deras initiala värden och hur de ändras efter varje iteration. "Ändra" -delen utvärderas i slutet av slingan. -
endlist
innehållerendlist
och värden som returneras i slutet av slingan. Slutvillkoret utvärderas i början av slingan.
Här är en som börjar på 0 och går upp till (inte inklusive) 10.
;;same as (dotimes (i 10))
(do (( i (+ 1 i))
((< i 10) i)
(print i))
Och här är en som går igenom en lista:
;;same as (dolist (item given-list)
(do ((item (car given-list))
(temp list (cdr temp))
(print item))
varlist
är lik den i ett let
uttalande. Du kan binda mer än en variabel, och de finns bara i slingan. Varje variabel som deklareras finns i sin egen uppsättning parentes. Här är en som räknar hur många 1 och 2 som finns i en lista.
(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)
Och om en makroslinga inte har implementerats:
(do ()
(t)
(when task-done
(break)))
För de vanligaste tillämpningarna är de mer specifika dotimes
och doloop
mycket mer kortfattade.