common-lisp
Контрольные структуры
Поиск…
Условные конструкции
В Common Lisp, if
это простейшая условная конструкция. Она имеет вид (if test then [else])
, then
test
else
(if test then [else])
и оценивается на then
, если test
верно и else
иначе. Часть else может быть опущена.
(if (> 3 2)
"Three is bigger!"
"Two is bigger!")
;;=> "Three is bigger!"
Одно очень важное различие между if
в Common Lisp и, if
во многих других языках программирования, это CL, if
это выражение, а не утверждение. Таким образом, if
формы возвращают значения, которые могут быть назначены переменным, используемые в списках аргументов и т. Д .:
;; Use a different format string depending on the type of x
(format t (if (numberp x)
"~x~%"
"~a~%")
x)
Общий Lisp, if
можно считать эквивалентным тернарному оператору?: В C # и других языках «фигурных скобок».
Например, следующее выражение C #:
year == 1990 ? "Hammertime" : "Not Hammertime"
Является эквивалентом следующего кода Common Lisp, считая, что year
содержит целое число:
(if (eql year 1990) "Hammertime" "Not Hammertime")
cond
- еще одна условная конструкция. Он несколько похож на цепочку операторов if
и имеет вид:
(cond (test-1 consequent-1-1 consequent-2-1 ...)
(test-2)
(test-3 consequent-3-1 ...)
... )
Точнее, cond
имеет нулевые или более предложения , и каждое предложение имеет один тест, за которым следуют ноль или более последовательных. Вся конструкция cond
выбирает первое предложение, тест которого не оценивается в nil
и оценивает его последующие порядки. Он возвращает значение последней формы в последующих.
(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!"
Чтобы предоставить предложение по умолчанию, чтобы оценить, не оценивает ли другое предложение значение t
, вы можете добавить предложение, которое истинно по умолчанию, используя t
. Это очень похоже на концепцию SQL CASE...ELSE
, но для выполнения задачи используется буквальное логическое значение true, а не ключевое слово.
(cond
((= n 1) "N equals 1")
(t "N doesn't equal 1")
)
Конструкция if
может быть записана как cond
конструкция. (if test then else)
и (cond (test then) (t else))
эквивалентны.
Если вам нужно только одно предложение, используйте, when
или 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
Большинство циклов и условных конструкций в Common Lisp на самом деле являются макросами, которые скрывают более основные конструкции. Например, dotimes
и dolist
построены на do
макрос. Форма для do
выглядит так:
(do (varlist)
(endlist)
&body)
-
varlist
состоит из переменных, определенных в цикле, их начальных значений и того, как они меняются после каждой итерации. Часть «изменения» оценивается в конце цикла. -
endlist
содержит конечные условия и значения, возвращаемые в конце цикла. Конечное условие оценивается в начале цикла.
Вот один, который начинается с 0 и идет вверх (не включая) 10.
;;same as (dotimes (i 10))
(do (( i (+ 1 i))
((< i 10) i)
(print i))
И вот тот, который перемещается по списку:
;;same as (dolist (item given-list)
(do ((item (car given-list))
(temp list (cdr temp))
(print item))
Часть varlist
похожа на varlist
в инструкции let
. Вы можете связывать более одной переменной, и они существуют только внутри цикла. Каждая объявленная переменная находится в своем собственном наборе скобок. Вот один из них, который подсчитывает количество 1 и 2 в списке.
(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)
И если макрос цикла while не был реализован:
(do ()
(t)
(when task-done
(break)))
Для наиболее распространенных приложений более конкретные dotimes
и doloop
макросы гораздо более кратки.