Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Pol_Grem_-_ANSI_Common_Lisp_High_tech_-_2012.pdf
Скачиваний:
28
Добавлен:
12.03.2016
Размер:
4.85 Mб
Скачать

250

Глава 14. Более сложные вопросы

как те, что изобра­же­ны­ на рис. 14.2, он может­ сделать­ код более­ доступ­­ ным для пони­ма­ния­.

(defun most (fn lst) (if (null lst)

(values nil nil)

(loop with wins = (car lst)

with max = (funcall fn wins) for obj in (cdr lst)

for score = (funcall fn obj) when (> score max)

do (setf wins obj max score)

finally (return (values wins max)))))

(defun num-year (n) (if (< n 0)

(loop for y downfrom (- yzero 1) until (<= d n)

sum (- (year-days y)) into d

finally (return (values (+ y 1) (- n d)))) (loop with prev = 0

for y from yzero until (> d n)

do (setf prev d)

sum (year-days y) into d finally (return (values (- y 1)

(- n prev))))))

Рис. 14.2. Итера­ция­ с помо­щью­ loop

14.6.Особые условия

ВCommon Lisp особые­ усло­вия­ (conditions) включа­ют­ ошибки­ и другие­ ситуа­ции,­ кото­рые­ могут­ возни­кать­ в процес­се­ выпол­не­ния­. Когда­ сиг­ нали­зи­ру­ет­ся­ какое­-либо­ усло­вие,­ вызы­ва­ет­ся­ соот­вет­ст­вую­щий­ обра­­ ботчик­. Обра­бот­чик­ по умолча­нию­ для усло­вий­-ошибок­ обычно­ вызы­ва­­ ет цикл преры­ва­ния­. Но Common Lisp предос­тав­ля­ет­ и разно­об­раз­ные­ опера­то­ры­ для сигна­ли­за­ции­ и обра­бот­ки­ усло­вий­. Вы може­те­ пере­оп­ре­­ делять­ уже суще­ст­вую­щие­ обра­бот­чи­ки­ и даже­ писать­ собст­вен­­ные.

Большин­ст­ву­ програм­ми­стов­ не придет­ся­ рабо­тать­ с особы­­ми усло­вия­­ ми непо­сред­ст­вен­­но. Одна­ко­ есть несколь­ко­ уровней­ более­ абст­ракт­ных­ опера­то­ров,­ кото­рые­ исполь­зу­ют­ усло­вия,­ поэто­му­ для их пони­ма­ния­ все же полез­но­ иметь представ­ле­ние­ о меха­низ­ме,­ изло­жен­ном­ ниже­.

14.6. Особые условия

251

В Common Lisp есть несколь­ко­ опера­то­ров­ для сигна­ли­за­ции­ об ошиб­ ках. Основ­ным­ явля­ет­ся­ error. Один из спосо­бов­ его вызо­ва ­– пере­да­ча­ ему тех же аргу­мен­тов,­ что и format:

> (error "Your report uses ~A as a verb." ’status) Error: Your report uses STATUS as verb.

Options: :abort, :backtrace

>>

Если­ такое­ усло­вие­ не обра­ба­ты­ва­ет­ся,­ вы­полне­ние­ будет­ прерва­но,­ как пока­за­но­ выше­.

Более­ абст­ракт­ны­ми­ опера­то­ра­ми­ для сигна­ли­за­ции­ ошибок­ явля­ют­ся­ ecase, check-type и assert. Первый­ напо­ми­на­ет­ case, но сигна­ли­зи­ру­ет­ об ошибке,­ когда­ не найде­но­ совпа­де­ние­ ни с одним­ ключом:­

> (ecase 1 (2 3) (4 5)) Error: No applicable clause.

Options: :abort, :backtrace

>>

Обычное­ case-выра­же­ние­ в этом случае­ вернет­ nil, но, посколь­ку­ счита­­ ется­ плохим­ стилем­ пользо­вать­ся­ этим возвра­щае­мым­ значе­ни­ем,­ име­ ет смысл приме­нить­ ecase, если­ у вас нет вари­ан­та­ otherwise.

Макрос­ check-type прини­ма­ет­ место,­ имя типа­ и необя­за­тель­ный­ аргу­­ мент-строку­. Он сигна­ли­зи­ру­ет­ о коррек­ти­руе­мой­ ошибке­, если­ значе­­ ние по данно­му­ месту­ не соот­вет­ст­ву­ет­ задан­но­му­ типу­. Обра­бот­чик­ коррек­ти­руе­мой­ ошибки­ предло­жит­ один из вари­ан­тов­ ее исправ­ле­ния:­

> (let ((x ’(a b c)))

(check-type (car x) integer "an integer") x)

Error: The value of (CAR X), A, should be an integer. Options: :abort, :backtrace, :continue

>> :continue

New value of (CAR X)? 99 (99 B C)

>

Только­ что мы приве­ли­ пример­ коррек­ции­ ошибки,­ испра­вив­ значе­ние­ (car x), после­ чего­ вы­полне­ние­ продол­жи­лось­ с исправ­лен­­ным значе­ни­­ ем, как будто­ оно было­ пере­да­но­ таким­ изна­чаль­но­.

Этот макрос­ был опре­де­лен­ с помо­щью­ более­ обще­го­ assert. Он прини­­ мает­ тесто­вое­ выра­же­ние­ и список­ одно­го­ или более­ мест, сопро­во­ж­дае­­ мый теми­ же аргу­мен­та­ми,­ кото­рые­ вы бы пере­да­ли­ в error:

> (let ((sandwich ’(ham on rye)))

(assert (eql (car sandwich) ’chicken) ((car sandwich))

"I wanted a ~A sandwich." ’chicken) sandwich)

252 Глава 14. Более сложные вопросы

Error: I wanted a CHICHEN sandwich.

Options: :abort, :backtrace, :continue >> :continue

New value of (CAR SANDWICH)? ’chicken (CHICKEN ON RYE)

>

Также­ имеет­ся­ возмож­ность­ созда­вать­ собст­вен­­ные обра­бот­чи­ки,­ но этим редко­ кто пользу­ет­ся­. Обычно­ обхо­дят­ся­ уже имеющи­ми­ся­ средст­­ вами,­ напри­мер­ ignore-errors. Этот макрос­ ведет­ себя­ анало­гич­но­ progn, если­ ни один из его аргу­мен­тов­ не приво­дит­ к ошибке­. Если­ же во время­ выпол­не­ния­ одно­го­ из выра­же­ний­ сигна­ли­зи­ру­ет­ся­ ошибка,­ то рабо­та­ не преры­­вает­ся,­ а выра­же­ние­ ignore-errors немед­лен­­но завер­ша­ет­ся­ с возвра­том­ двух значе­ний:­ nil и усло­вия,­ кото­рое­ было­ просиг­на­ли­зи­­ рова­но­.

Напри­мер,­ если­ вы даете­ пользо­ва­те­лю­ возмож­ность­ вводить­ собст­вен­­ ные выра­же­ния,­ но не хоти­те,­ чтобы­ синтак­си­че­ски­ невер­ное­ выра­же­­ ние преры­­вало­ рабо­ту,­ то вам пона­до­бит­ся­ защи­та­ от некор­рект­но­ сфор­ миро­ван­ных­ выра­же­ний:­

(defun user-input (prompt) (format t prompt)

(let ((str (read-line)))

(or (ignore-errors (read-from-string str)) nil)))

Функция­ вернет­ nil, если­ считан­ное­ выра­же­ние­ содер­жит­ синтак­си­че­­ скую ошибку:­

> (user-input "Please type an expression> ") Please type an expression> #%@#+!!

NIL

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]