…,functor(Заголовок,Func,Arity),functor(Proc,Func,Arity),…
конкретизирует Ргосструктурой, имеющей тот же функтор, что и заголовок Заголовок, но с переменными в качестве аргументов (см. разд. 6.5).
ГЛАВА 8. ОТЛАДКА ПРОЛОГ-ПРОГРАММ
На приведенных выше примерах вы уже приобрели опыт применения программ и научились их изменять, а также успели написать и свои собственные программы. Теперь самое время заняться вопросом: что делать, когда программа ведет себя не так, как ожидалось. Подобные неожиданности связаны с наличием ошибок в программе, а процесс устранения этих ошибок называется отладкой. По нашему убеждению самым разумным подходом к программированию является тот, который может быть охарактеризован как «программирование с предупреждением ошибок». Перефразируя старую поговорку, можно сказать, что грамм тщательного программирования стоит килограмма отладки. В этой главе мы расскажем о некоторых методах отладки, но начнем с того, как избежать проникновения ошибок в программы. Сознавая, что в общем виде эта проблема неразрешима, мы хотим просто поделиться некоторыми неформальными приемами, которые уже приносили пользу другим программистам, работающим на Прологе.
Как и всякое творчество, будь то сочинение музыки, литература или архитектура, программирование располагает множеством способов представления объектов и обработки этих объектов и отношений между ними в конкретной программе. В общем случае для некоторого элемента данных в программе существует несколько возможных способов его представления или обработки. Всякий раз, когда программист решает использовать в данной программе один из них, мы говорим, что программист принял проектное решение.
Новички, впервые столкнувшиеся с задачей выбора проектных решений, часто испытывают трудности. Помочь им может знание возможных вариантов решений, и, кроме того, важно, чтобы руководитель разъяснил им методику программирования в целом, поскольку искусство принятия проектных решений в программировании – это самостоятельная дисциплина. Мы уже пытались затронуть эту проблему в разд. 1.1, где обсуждались различные способы интерпретации утверждений. Эти вопросы связаны с представлением объектов и отношений. В разд. 7.7 мы снова столкнулись с этой проблемой при описании трех различных способов упорядочения списка объектов. Эти вопросы связаны с разными способами обработки объектов и отношений.
В данной книге мы старались оказать помощь в выборе проектных решений двумя путями. Во-первых, наличие в книге большого числа примеров программ должно способствовать усвоению идей некоторых решений, выработанных опытными программистами. Во-вторых, в данной главе можно найти некоторые советы и рекомендации, специфические для Пролога.
8.1. Расположение текстов программ
После того как программист принял решение о том, как представлять и обрабатывать объекты и отношения в программе, ему следует убедиться в том, что текст программы расположен удобно для чтения и ее синтаксические конструкции ясны. Набор утверждений для данного предиката называется процедурой. Возможно, вы уже обратили внимание на то, что в примерах данной книги каждое утверждение в процедуре начинается с новой строки, а между собой процедуры разделяются одной пустой строкой. Например, один из способов определения предиката эквивалентности для множеств (при представлении множеств в виде списков) состоит в использовании трех предикатов, каждый из которых определяется с помощью процедуры из двух строк:
равмнож(Х,Х):-!.
равмнож(Х,Y):- равспис(Х,Y).
равспис([],[]).
равспис([Х|L1],L2):- удалить(Х,L2,LЗ), равспис(L1,LЗ).
удалить(Х,[Х|Y],Y).
удалить(Х,[Y|L1],[Y|L2]):- удалить(Х,L1,L2).
Данный пример, возможно, не является наилучшим определением эквивалентности множеств, однако он показывает, как нужно размещать тексты процедур. Заметим, что утверждения каждой процедуры сгруппированы вместе, а процедуры разделяются пустой строкой. Другое соглашение, которого придерживаются многие программисты на Прологе, - это писать каждое утверждение на отдельной строке, если оно на ней умещается. Если нет, то писать заголовок утверждения и знак ':-' на первой строке, а каждую цель в конъюнкции целей писать с новой строки со сдвигом. Для примера рассмотрим запись программы порождения всех перестановок списка:
перест([],[]).
перест(L,[Н|Т]):-
присоединить(Y,[Н|U],L),
Читать дальше