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

12.8. Неизменяемая структура

217

(setf (elt-parent c) p (elt-child p) c)

c))

#1=#S(ELT PARENT #S(ELT PARENT NIL CHILD #1#) CHILD NIL)

Для печа­ти­ подоб­ных­ структур­ необ­хо­ди­мо­ уста­но­вить­ *print-circle* в t или же избе­гать­ выво­да­ таких­ объек­тов­.

12.8. Неизменяемая структура

Неиз­ме­няе­мые­ объек­ты­ также­ явля­ют­ся­ частью­ кода,­ и наша­ зада­ча­ не допус­кать­ их моди­фи­ка­ции,­ пото­му­ что в против­ном­ случае­ мы случай­­ но можем­ создать­ програм­му,­ кото­рая­ пишет­ сама­ себя­. Цити­руе­мый­ список­ явля­ет­ся­ констан­той,­ поэто­му­ следу­ет­ прояв­лять­ акку­рат­ность­ при рабо­те­ с отдель­ны­ми­ его ячейка­ми­. Напри­мер,­ если­ мы исполь­зу­ем­ следую­щий­ преди­кат­ для провер­ки­ на при­надлеж­­ность к арифме­ти­че­­ ским опера­то­рам,­

(defun arith-op (x) (member x ’(+ - * /)))

то в случае­ истин­но­го­ значе­ния­ он будет­ возвра­щать­ часть цити­руе­мо­го­ списка­. Изме­няя­ возвра­щае­мое­ значе­ние:­

> (nconc (arith-op ’*) ’(as it were)) (* / AS IT WERE)

мы изме­ня­ем­ и сам исход­ный­ список­ внутри­ arith-op, что приве­дет­ к из­ мене­нию­ рабо­ты­ этой функции:­

> (arith-op ’as) (AS IT WERE)

Возврат­ констан­ты­ из функции­ не всегда­ явля­ет­ся­ ошибкой­. Одна­ко­ нужно­ учиты­вать­ подоб­ные­ случаи­ при при­нятии­ реше­ния­ о безопас­­ ности­ выпол­не­ния­ дест­рук­тив­ных­ опера­ций­ над чем-либо­.

Избе­жать­ возвра­та­ части­ неиз­мен­ной­ структу­ры­ в случае­ arith-op мож­ но несколь­ки­ми­ спосо­ба­ми­. В общем­ случае­ заме­на­ цити­ро­ва­ния­ на яв­ ный вызов­ функции­ list решит­ пробле­му­ и приве­дет­ к созда­нию­ ново­го­ списка­ при каждом­ вызо­ве:­

(defun arith-op (x)

(member x (list ’+ ’- ’* ’/)))

Одна­ко­ в данном­ случае­ вызов­ list ударит­ по произ­во­ди­тель­но­сти,­ по­ этому­ здесь лучше­ вместо­ member исполь­зо­вать­ find:

(defun arith-op (x) (find x ’(+ - * /)))

Пробле­ма,­ рассмот­рен­ная­ в этом разде­ле,­ чаще­ всего­ возни­ка­ет­ при ра­ боте­ со списка­ми,­ одна­ко­ она акту­аль­на­ и для других­ типов­ данных:­

218

Глава 12. Структура

масси­вов,­ строк, структур,­ экзем­п­ля­ров­ и т. д. Не следу­ет­ моди­фи­ци­ро­­ вать что-либо,­ задан­ное­ в тексте­ програм­мы­ бук­валь­но­.

Даже­ если­ вы соби­рае­тесь­ напи­сать­ само­мо­ди­фи­ци­руе­мую­ програм­му,­ изме­не­ние­ структур­-констант ­– это непра­виль­ный­ выбор­. Ком­пиля­тор­ может­ связы­­вать констан­ты­ с кодом,­ а дест­рук­тив­ные­ опера­то­ры­ мо­ гут изме­нять­ свои аргу­мен­ты,­ но ни то, ни другое­ не гаран­ти­ру­ет­ся­. Писать­ само­мо­ди­фи­ци­руе­мые­ програм­мы­ вы може­те,­ напри­мер,­ с по­ мощью­ замы­ка­ний­ (см. раздел 6.5).

Итоги главы

1.Два списка­ могут­ разде­лять­ общий­ хвост. Списки­ могут­ разде­лять­ структу­ры­ как дере­вья,­ без разде­ле­ния­ структу­ры­ верхне­го­ уровня­. Разде­ле­ния­ структур­ можно­ избе­жать­ с помо­щью­ копи­ро­ва­ния­.

2.Разде­ляе­мость­ структу­ры­ не влияет­ на пове­де­ние­ функций,­ но о ней нельзя­ забы­­вать, если­ вы соби­рае­тесь­ моди­фи­ци­ро­вать­ списки­. Если­ два списка­ разде­ля­ют­ общую­ структу­ру,­ то изме­не­ние­ одно­го­ из них может­ привес­ти­ к изме­не­нию­ друго­го­.

3.Очере­ди­ могут­ быть представ­ле­ны­ как cons-ячейки,­ car кото­рых­ ука­ зы­вает­ на первую­ ячей­ку списка,­ а cdr – на послед­нюю­.

4.Из сооб­ра­же­ний­ произ­во­ди­тель­но­сти­ дест­рук­тив­ным­ опера­то­рам­ раз­ реша­ет­ся­ моди­фи­ци­ро­вать­ свои аргу­мен­ты­.

5.В неко­то­рых­ прило­же­ни­ях­ исполь­зо­ва­ние­ дест­рук­тив­ных­ опера­то­­ ров более­ есте­ст­вен­­но.

6.Списки­ могут­ быть цикли­че­ски­ми­ по голо­ве­ и хвосту­. Лисп умеет­ рабо­тать­ с цикли­че­ски­ми­ и разде­ляе­мы­ми­ структу­ра­ми­.

7.Не следу­ет­ изме­нять­ констан­ты,­ встречаю­щие­ся­ в тексте­ програм­мы­.

Упражнения

1.Нари­суй­те­ три различ­ных­ дере­ва,­ кото­рые­ будут­ выво­дить­ся­ как ((A) (A) (A)). Напи­ши­те­ выра­же­ния,­ гене­ри­рую­щие­ каждое­ из них.

2.Считая­ уже опре­де­лен­ны­ми­make-queue, enqueue и dequeue (см. рис. 12.7), нари­суй­те­ представ­ле­ние­ очере­ди­ в виде­ ячеек­ после­ каждо­го­ сле­ дующе­го­ шага:­

>(setf q (make-queue)) (NIL)

>(enqueue ’a q)

(A)

>(enqueu ’b q) (A B)

>(dequeue q)

A

Упражнения

219

3.Опре­де­ли­те­ функцию­ copy-queue, возвра­щаю­щую­ копию­ очере­ди­.

4.Опре­де­ли­те­ функцию,­ прини­маю­щую­ в каче­ст­ве­ аргу­мен­тов­ объект­

иочередь­ и поме­щаю­щую­ этот объект­ в нача­ло­ очере­ди­.

5.Опре­де­ли­те­ функцию,­ прини­маю­щую­ в каче­ст­ве­ аргу­мен­тов­ объект­

иочередь­ и (дест­рук­тив­но)­ пере­ме­щаю­щую­ первый­ найден­ный­ (eql) экзем­п­ляр­ этого­ объек­та­ в нача­ло­ очере­ди­.

6.Опре­де­ли­те­ функцию,­ прини­маю­щую­ объект­ и цикли­че­ский­ спи­ сок, кото­рый­ может­ быть цикли­че­ским­ по хвосту,­ и прове­ряю­щую­ нали­чие­ задан­но­го­ объек­та­ в списке­.

7.Опре­де­ли­те­ функцию,­ прове­ряю­щую,­ явля­ет­ся­ ли ее аргу­мент­ цик­ личе­ским­ по хвосту­ списком­.

8.Опре­де­ли­те­ функцию,­ прове­ряю­щую,­ явля­ет­ся­ ли ее аргу­мент­ цик­ личе­ским­ по голо­ве­ списком­.

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