common-lisp
Struktury kontrolne
Szukaj…
Konstrukcje warunkowe
W Common Lisp, if
jest najprostszą konstrukcją warunkową. Ma on formę (if test then [else])
i ocenia się then
, jeśli test
jest prawdziwe, else
inaczej. Inną część można pominąć.
(if (> 3 2)
"Three is bigger!"
"Two is bigger!")
;;=> "Three is bigger!"
Jedna bardzo ważna różnica między if
w Common Lisp i if
w wielu innych językach programowania jest to, że CL if
jest wyrazem, a nie stwierdzenie. Jako taki, if
formularze zwracają wartości, które można przypisać do zmiennych, używanych na listach argumentów itp .:
;; Use a different format string depending on the type of x
(format t (if (numberp x)
"~x~%"
"~a~%")
x)
Typowe Lisp, if
można je uznać za równoważne z operatorem potrójnym?: W języku C # i innych językach nawiasów klamrowych.
Na przykład następujące wyrażenie C #:
year == 1990 ? "Hammertime" : "Not Hammertime"
Odpowiada poniższemu wspólnemu kodowi Lisp, przy założeniu, że year
ma liczbę całkowitą:
(if (eql year 1990) "Hammertime" "Not Hammertime")
cond
to kolejna konstrukcja warunkowa. Jest nieco podobny do łańcucha instrukcji if
i ma postać:
(cond (test-1 consequent-1-1 consequent-2-1 ...)
(test-2)
(test-3 consequent-3-1 ...)
... )
Dokładniej, cond
ma zero lub więcej klauzul , a każda klauzula ma jeden test, po którym następuje zero lub więcej następstw. Cały konstrukt cond
wybiera pierwszą klauzulę, której test nie jest nil
i ocenia kolejno następstwa. Zwraca wartość ostatniej formy w wynikach.
(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!"
Aby zapewnić domyślną klauzulę do oceny, czy żadna inna klauzula nie ocenia na t
, możesz dodać klauzulę, która jest domyślnie prawdziwa, używając t
. Jest to bardzo podobne w koncepcji do instrukcji CASE...ELSE
SQL, ale do wykonania zadania używa dosłownie logicznej wartości prawda, a nie słowa kluczowego.
(cond
((= n 1) "N equals 1")
(t "N doesn't equal 1")
)
Konstrukt if
można zapisać jako konstrukt cond
. (if test then else)
i (cond (test then) (t else))
są równoważne.
Jeśli potrzebujesz tylko jednej klauzuli, użyj when
lub o 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
Pętla do
Większość zapętlonych i warunkowych konstrukcji w Common Lisp to tak naprawdę makra, które ukrywają bardziej podstawowe konstrukcje. Na przykład, dotimes
i dolist
są zbudowane na do
makro. Formularz do
wygląda następująco:
(do (varlist)
(endlist)
&body)
-
varlist
składa się ze zmiennych zdefiniowanych w pętli, ich wartości początkowych i tego, jak zmieniają się po każdej iteracji. Część „zmiany” jest oceniana na końcu pętli. -
endlist
zawiera warunki końcowe i wartości zwracane na końcu pętli. Stan końcowy jest oceniany na początku pętli.
Oto ten, który zaczyna się od 0 i idzie w górę do (bez) 10.
;;same as (dotimes (i 10))
(do (( i (+ 1 i))
((< i 10) i)
(print i))
A oto jedna, która porusza się po liście:
;;same as (dolist (item given-list)
(do ((item (car given-list))
(temp list (cdr temp))
(print item))
Część varlist
jest podobna do tej w instrukcji let
. Możesz powiązać więcej niż jedną zmienną, a one istnieją tylko w pętli. Każda deklarowana zmienna ma własny zestaw nawiasów. Oto jeden, który liczy, ile 1 i 2 jest na liście.
(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)
A jeśli makro pętli while nie zostało zaimplementowane:
(do ()
(t)
(when task-done
(break)))
W przypadku najczęstszych zastosowań bardziej szczegółowe makra dotimes
i doloop
są znacznie bardziej zwięzłe.