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 макросы гораздо более кратки.