1 / 20

Логическое программировыание

Логическое программировыание. Презентация 9 Отладка Пролог-программ. Содержание. Основные критерии и правила написания программ Предикаты для отладки и трассировки программ Множество решений. Предикаты порождения. Критерии оценки программ.

Download Presentation

Логическое программировыание

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Логическое программировыание Презентация 9 Отладка Пролог-программ

  2. Содержание • Основные критерии и правила написания программ • Предикаты для отладки и трассировки программ • Множество решений. Предикаты порождения

  3. Критерии оценки программ • Правильность. Хорошая программа в первую очередь должна быть правильной, т. е. она должна делать именно то, для чего предназначалась. Это требование может показаться тривиальным и самоочевидным. Однако в случае сложных программ правильность достигается не так часто. Распространенной ошибкой при написании программ является пренебрежение этим очевидным критерием, когда большее внимание уделяется другим критериям - таким, как эффективность. • Эффективность. Хорошая программа не должна попусту тратить компьютерное время и память. • Простота, читабельность. Хорошая, программа должна быть легка для чтения и понимания. Она не должна быть более сложной, чем это необходимо. Следует избегать хитроумных программистских трюков, затемняющих смысл программы. Общая организация программы и расположение ее текста должны облегчать ее понимание. • Удобство модификации. Хорошая программа должна быть легко модифицируема и расширяема. Простота и модульная организация программы облегчают внесение в нее изменений. • Живучесть. Хорошая программа должна быть живучей. Она не должна сразу "ломаться", если пользователь введет в нее неправильные или непредусмотренные данные. В случае подобных ошибок программа должна сохранять работоспособность и вести себя разумно (сообщать об ошибках). • Документированность. Хорошая программа должна быть хорошо документирована. Минимальная документация - листинг с достаточно подробными комментариями.

  4. Правила написания программ Чтобы писать программы, которые легко читать, понимать, отлаживать и модифицировать, нужно придерживаться следующих правил: • Предложения для одного предиката нужно группировать вместе, разделяя определения пустой строкой. • Каждое предложение нужно начинать с первой позиции и делать отступ для частей предложения, не поместившихся в одной строке. • Предложения должны быть по возможности короткими. • Имена предикатов и переменных должны отражать их назначение. • Предикаты !, not, assert и retract следует применять с осторожностью. • Число дизъюнкций в программе следует уменьшать, разделяя правила на несколько предложений или вводя новые предикаты. • Комментарии должны отражать все возможные способы использования предиката,какие аргументы должны быть конкретизированы, какой тип значений допустим, какие аргументы являются выходными. • В первых предложениях определения должны анализироваться частные случаиприменения предиката, а первые цели в теле правила должны проверять наиболеепростые отношения.

  5. После реализации… После написания программы рекомендуется: • проверить, что в конце каждого предложения стоит точка; • проверить имена и количество аргументов у каждого предиката, включая встроенные, так как неверное имя или пропущенный аргумент дает заведомо неуспешную цель; • проверить введенные операторы, их приоритет и ассоциативность, используя display, в сложных случаях поставить скобки. • Следует соблюдать стиль! Подчиняться при программировании некоторым стилистическим соглашениям нужно для того, чтобы • уменьшить опасность внесения ошибок в программы и • создавать программы, которые легко читать, понимать, отлаживать и модифицировать.

  6. Использование рисунков • В поиске идей для решения задачи часто бывает полезным обратиться к ее графическому представлению. Рисунок может помочь выявить в задаче некоторые существенные отношения. После этого останется только описать на языке программирования то, что мы видим на рисунке. • Использование графического представления при решении задач полезно всегда, однако похоже, что в Прологе оно работает особенно хорошо. Происходит это по следующим причинам: • Пролог особенно хорошо приспособлен для задач, в которых фигурируют объекты и отношения между ними. Часто такие задачи естественно иллюстрировать графами, в которых узлы соответствуют объектам, а дуги - отношениям. • Естественным наглядным изображением структурных объектов Пролога являются деревья. • Декларативный характер пролог-программ облегчает перевод графического представления на Пролог. В принципе, порядок описания "картинки" не играет роли, мы просто помещаем в программу то, что видим, в произвольном порядке. (Возможно, что из практических соображений этот порядок впоследствии придется подправить с целью повысить эффективность программы.)

  7. Комментирование • Программные комментарии должны объяснять в первую очередь, для чего программа предназначена и как ею пользоваться, и только затем - подробности используемого метода решения и другие программные детали. Главная цель комментариев - обеспечить пользователю возможность применять программу, понимать ее и, может быть, модифицировать. Комментарии должны содержать в наиболее краткой форме всю необходимую для этого информацию. Недостаточное комментирование - распространенная ошибка, однако, программу можно и перенасытить комментариями. Объяснения деталей, которые и так ясны из самого текста программы, являются ненужной перегрузкой. • Длинные фрагменты комментариев следует располагать перед текстом, к которому они относятся, в то время как короткие комментарии должны быть вкраплены в сам текст. Информация, которую в самом общем случае следует включать в комментарии, должна схватывать следующие вопросы: • Что программа делает, как ею пользоваться (например, какую цель следует активизировать и каков вид ожидаемых результатов), примеры ее применения. • Какие предикаты относятся к верхнему уровню? • Как представлены основные понятия (объекты)? • Время выполнения и требования по объему памяти. • Каковы ограничения на программу? • Использует ли она какие-либо средства, связанные с конкретной операционной системой? • Каков смысл предикатов программы? Каковы их аргументы? Какие аргументы являются "входными" и какие - "выходными", если это известно? (В момент запуска предиката входные аргументы имеют полностью определенные значения, не содержащие не конкретизированных переменных.) • Алгоритмические и реализационные детали.

  8. Типичные ошибки К наиболее типичным ошибкам при разработке программ на языке Пролог можно отнести следующие ошибки. • После создания или изменения программы не выполняется ее преобразование во внутреннее представление с помощью reconsult. • Программа содержит циклические рекурсивные определения, которые требуют согласования цели, эквивалентной исходной, и часто связаны с левосторонней ре­курсией. • Рассмотрены не все случаи для завершения рекурсии или указаны неправильные условия • Указано неверное количество аргументов у функтора, что приведет к неудаче при поиске правила для обработки структуры. • Результатом применения программ, содержащих ошибки, обычно является зацик­ливание или переполнение стека, отрицательные ответы или конкретизация переменных не теми ответами, которые ожидались.

  9. Отладка программ • Когда программа не делает того, чего от нее ждут, главной проблемой становится отыскание ошибки (или ошибок). Всегда легче найти ошибку в какой-нибудь части программы (или в отдельном модуле), чем во всей программе. Поэтому следует придерживаться следующего хорошего принципа: проверять сначала более мелкие программные единицы и только после того, как вы убедились, что им можно доверять, начинать проверку большего модуля или всей программы. • Отладка в Прологе облегчается двумя обстоятельствами: • Пролог - интерактивный язык, поэтому можно непосредственно обратиться к любой части программы, задав пролог-системе соответствующий вопрос; • В реализациях Пролога обычно имеются специальные средства отладки. • Следствием этих двух обстоятельств является то, что отладка программ на Прологе может производиться, вообще говоря, значительно эффективнее, чем в других языках программирования.

  10. Трассировка • Основным средством отладки является трассировка (tracing). "Трассировать цель" означает: предоставить пользователю информацию, относящуюся к достижению этой цели в процессе ее обработки пролог-системой. Эта информация включает: • Входную информацию - имя предиката и значении аргументов в момент активизации цели. • Выходную информацию - в случае успеха, значения аргументов, удовлетворяющих цели; в противном случае - сообщение о неуспехе. • Информацию о повторном входе, т. е. об активизации той же цели в результате автоматического возврата. • В промежутке между входом и выходом можно получить трассировочную информацию для всех подцелей этой цели. Т.о., мы можем следить за обработкой нашего вопроса на всем протяжении нисходящего пути от исходной цели к целям самого нижнего уровня, вплоть до отдельных фактов. • Такая детальная трассировка может оказаться непрактичной из-за непомерно большого количества трассировочной информации. Поэтому пользователь может применить селективную трассировку (указав трассируемый предикат).

  11. Пример трассировки • Режим трассировки включается с помощью предиката trace, а выключается notrace; в качестве аргумента можно указать имя трассируемого предиката. •  Предикат spy( P), «следи за Р» - устанавливает режим контролируемойпошаговой трассировки предиката Р. Обращение к spy применяют, когда хотят получить информацию только об указанном предикате и избежать трассировочной информации от других целей (выше/ниже уровня запуска Р). nospy( Р) прекращает "слежку" за Р. Обычный запуск: fact(1,1):-!. fact(N,F):- N1 is N-1, fact(N1,F1), F is F1*N. ?- fact(3,X). X = 6 ; No Запуск в режиме трассировки: ?- trace(fact). % fact/2: [call, redo, exit, fail] Yes [debug] 2 ?- fact(3,X). T Call: (7) fact(3, _G429) T Call: (8) fact(2, _L170) T Call: (9) fact(1, _L189) T Exit: (9) fact(1, 1) T Exit: (8) fact(2, 2) T Exit: (7) fact(3, 6) X = 6 ;

  12. События трасировки В процессе выполнения программ на языке Пролог могут происходить следующие 4события: • Событие CALLфиксирует начало попытки Пролога согласовать цель с БД Печатается цель. • СобытиеEXITфиксирует момент, когда некоторая цель только что согласована с БД Печатается согласо­ванная цель. • Событие REDOфиксирует момент, когда система возвращается к цели, пытаясь повторно согласовать ее с БД. Печатается согласованная цель • Событие FAIL фиксирует момент, когда попытка согласовать цель с БД заканчивается неудачно. Печатается цель.

  13. Действия при отладке • При наступлении события Пролог печатает цель и ожидает ввода команды. Можно ввести одну из следующих команд: • h[elp] - помощь; • пробел - переключить окна; • c[reep] или Enter - идти к следующему событию; • s[kip] или Esc - не останавливаться до наступления события EXIT или FAIL для текущей цели (рекомендуется использовать для уже отлаженных предикатов); • a[bort] - завершить выполнение программы. ?- spy(fact). % Spy point on fact/2 Yes [debug] 2 ?- fact(3, X). Call: (7) fact(3, _G435) ? creep% нажали Enter ^ Call: (8) _L169 is 3-1 ? skip % нажали S ^ Exit: (8) 2 is 3-1 ? Abort % нажали A % Execution Aborted

  14. Повышение эффективности работы программ • Прогон откомпилированной программы обычно имеет большую эффективность, чем интерпретация. Поэтому, если пролог-система содержит как интерпретатор, так и компилятор, следует пользоваться компилятором, если время выполнения критично. • Существует много способов повышения эффективности программы. Наиболее простые способы включают в себя: • изменение порядка целей и предложений • управляемый перебор при помощи введения отсечений • запоминание (с помощью assert) решений, которые требуется перевычислять • Более тонкие и радикальные методы связаны с улучшением алгоритмов (особенно, в части повышения эффективности перебора) и с совершенствованием структур данных. • Полезные идеи, относящиеся к повышению эффективности, обычно возникают только при достижении более глубокого понимания задачи. • Более эффективный алгоритм может привести к улучшениям двух видов: • Повышение эффективности поиска путем скорейшего отказа от ненужного перебора и от вычисления бесполезных вариантов. • Применение cтруктур данных, более приспособленных для представления объектов программы, с целью реализовать операции над ними более эффективно.

  15. Предикаты порождения • Мы можем получить все решения для некоторой цели одно за другим с помощью перебора, но при получении нового решения предыдущее становится недоступным. Предикаты порождения позволяют получить доступ ко всем решениям сразу, собирая их в список. • Для получения множества всевозможных решений можно использовать следующий встроенные предикаты: • bagof – все возможные решения, в т.ч. Дубликаты • setof – все возможные решения, отсортированные и без дубликатов • findall– решения без альтернативных конкретизаций • Рассмотрим их подробнее…

  16. Предикат bagof • Предикат bagof(X,P,L) порождает список L всех объектов X, удовлетворяющих цели Р. • X и Р должны содержать общие переменные. Если нет ни одного решения, то согла­сование цели завершается неудачей. Если один и тот же X найден многократно, то все его экземпляры будут в списке. • Пример: ищем потомков через отношение «предок» • ?- ancestor('Каин', X). • X = 'Алиса' • X = 'Диана' ; • X = 'Мадонна' ; • X = 'Александр' ; • X = 'Эрнест '; • X = 'Альберт' ; • X = 'Марианна' ; • X = 'Кристина' ; • X = 'Марианна' ; • ?- bagof(X, ancestor('Каин', X), L). • L = ['Алиса', 'Диана', 'Мадонна', 'Александр', 'Эрнест', 'Альберт', 'Марианна', 'Барбара', 'Роза'|...] • Если цель будет содержать другие неконкретизированные переменные, то для ка­ждой из возможных конкретизаций этих переменных получается свой список решений: • ?- bagof(X, ancestor(Y, X), L). • Y = 'Адам' • L = ['Каин', 'Авель', 'Сара', 'Алиса', 'Диана', 'Мадонна', 'Александр', 'Эрнест', 'Альберт'|...];

  17. Предикат setof • Предикат setof(X,P,L) работает аналогично bagof, но список L будетупорядочен и не будет содержать повторяющихся элементов. • ?- setof(X, ancestor('Каин', X), L). L = ['Александр', 'Алиса', 'Альберт', 'Барбара', 'Диана', 'Кристина', 'Мадонна', 'Марианна', 'Роза'|...] ; • Убедимся, что нет повторов: применим предикат для печати списка: print_list([X]):- write(X), nl. print_list([X|T]):- write(X), nl, print_list(T). setof(X, ancestor('Каин', X), L), print_list(L). Александр Алиса Альберт Барбара Диана Кристина Мадонна Марианна Роза Филипп Эрнест

  18. Предикат findall • Предикат findall(X, P, L) отличается от предиката bagof тем, что собирает в список L все объекты X, удовлетворяющие цели Р, не обращая внимания на конкретизации тех переменных, которых нет в X. • Если не существует ни одного решения, то цель findall(X,P,L) все равно успешна и L=[ ]. • ?- findall(X, ancestor(Y, X), L). X = _G369 Y = _G368 L = ['Каин', 'Авель', 'Сара', 'Мэри', 'Майкл', 'Алиса', 'Диана', 'Мадонна', 'Барбара'|...] ; No

  19. Сравнение findall/bagof/setof

  20. Выводы • Существует ряд правил, следование которым позволяет сократить количество ошибок в разрабатываемых программах. • Для оценки качества программы существует несколько критериев: правильность, эффективность, простота, читабельность, удобство модификации,документированность • Принцип пошаговой детализации - хороший способ организации процесса разработки программ. Пошаговая детализация применима к отношениям, алгоритмам и структурам данных. • Следующие методы помогают находить идеи для совершенствования программ: • Применение рекурсии:  выявить граничные и общие случаи рекурсивного определения. • Обобщение:  рассмотреть такую более общую задачу, которую проще решить, чем исходную. • Использование рисунков:  графическое представление помогает в выявлении отношений. • Полезно следовать некоторым стилистическим соглашениям для уменьшения опасности внесения ошибок в программы и создания программ, легких для чтения, отладки и модификации. • В пролог-системах обычно имеются средства отладки. Наиболее полезными являются средства трассировки программ. • Следует заботиться об эффективности реализации программ, наряду с их правильностью. • Часто требуется получить множество решений, возвращаемых предикатом, в виде единого списка; для этого удобно воспользоваться предикатами порождения.

More Related