Каковы лучшие методы программирования Prolog и рекомендации по стилю?

Хорошо, я знаю, что это очень общий вопрос и что были написаны некоторые статьи по этому вопросу, но у меня есть ощущение, что эти публикации охватывают очень простой материал, и я ищу что-то более продвинутое, что улучшит стиль и Efficency. Это то, что у меня есть в документе:

  • "Исследовательский отчет AI-1989-08" Эффективный пролог: практическое руководство "Майкла А. Ковингтона, 1989 г.
  • "Эффективное программирование пролога" Тимо Кнутила, 1992 г.
  • "Руководства по кодированию для Prolog" от Covington, Bagnara, O'Keefe, Wielemaker, Price, 2011

Образцы, охватываемые в этих разделах: хвостовая рекурсия и дифференциальные списки, правильное использование индексирования, правильное использование разрезов, исключение утверждений и отводов, исключение CONSING, рекомендации по форматированию кода (отступы, if-then-elses и т.д.), соглашения об именах, документирование кода, порядок аргументов, тестирование.

Что бы вы добавили здесь из своего личного опыта с Prolog? Существуют ли специальные правила стиля, применимые только к программированию CLP? Знаете ли вы о некоторых проблемах с общей эффективностью и знаете, как с ними бороться?

UPDATE:

Некоторые интересные (но все же слишком простые и слишком общие для меня) пункты сделаны здесь: Инструкции по программированию Prolog команды Lifeware

Просто чтобы выделить всю проблему, я хотел бы ответить "Правила кодирования для Prolog" (Covington и др.):

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

Ответы

Ответ 1

Для проектирования чистых интерфейсов в Prolog я рекомендую прочитать стандарт Prolog, см. .

В частности, конкретный формат кодирования встроенных предикатов, который включает определенный стиль документации, а также способ передачи ошибок. См. 8.1. Формат встроенных определений предикатов ISO/IEC 13211-1:1995. Вы найдете определения в этом стиле в Интернете Cor.2 и Пролог пролога.

Хорошим примером библиотеки, которая следует за соглашениями об ошибках ISO, вплоть до буквы (и пока не стандартизирована), является реализация library(clpfd) в SICStus и SWI. Хотя обе реализации принципиально отличаются в своем подходе, они используют соглашения об ошибках в своих лучших интересах.

Назад к ISO. Это формат ISO для встроенных предикатов:

x.y.z Название /Arity

В начале может быть короткое необязательное неофициальное замечание.

x.y.z.1 Описание

Дается декларативное описание, которое начинается очень часто с самой общей цели с использованием описательных имен переменных, чтобы они могли быть упомянуты позже. Если значение предиката вообще не декларативно, оно либо указано "истинно", либо какое-то другое ненужное вводящее в действие слово "унифицирует", "собирает". Позвольте мне привести пример:

8.5.4 copy_term/2

8.5.4.1 Описание

copy_term(Term_1, Term_2) истинно, если if Term_2 объединяется с термином T, который является переименованной копией (7.1.6.2) в Term_1.

Таким образом, это унифицирует большой красный предупреждающий знак: никогда не думайте, что этот предикат является отношением, его можно понять только процедурно. И тем более он (неявно) утверждает, что определение во втором аргументе устойчиво.

Другой пример: sort/2. Это теперь отношение или нет?

8.4.3 sort/2

8.4.3.1 Описание

sort(List, Sorted) истинно, если if Sorted объединяется с отсортированным списком List (7.1.6.5).

Так, опять же, никакого отношения. Удивлены? Посмотрите 8.4.3.4 Примеры:

8.4.3.4 Примеры

...

sort([X, 1], [1, 1]).
   Succeeds, unifying X with 1.

sort([1, 1], [1, 1]).
   Fails.

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

x.y.z.2 Шаблон и режимы

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

8.5.2.2 Шаблон и режимы

arg(+integer, +compound_term, ?term)

Существует, однако, большая разница между подходом ISO и Covington et al. который носит неформальный характер и указывает, как программист должен использовать предикат. Подход ISO описывает, как будет себя вести встроенный - в частности, какие ошибки следует ожидать. (Из вышеприведенных ошибок 4 ошибки плюс одна дополнительная ошибка, которая не может быть видна из вышеприведенной спецификации, см. Ниже).

x.y.z.3 Ошибки

Даны все условия ошибки, каждый в своем собственном подпункте, пронумерованном в алфавитном порядке. Кодекс в 7.12 Ошибки:

Когда выполняется более одного условия ошибки, ошибка, сообщаемая процессором Prolog, зависит от реализации.

Это означает, что каждое условие ошибки должно содержать все предварительные условия, в которых оно применяется. Все они. Условия ошибки не читаются, как if-then-elsif-then...

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

Многие условия ошибки непосредственно следуют из спецификации, указанной в xyz2 в соответствии с ПРИМЕЧАНИЯми в 8.1.3 Ошибки и в соответствии с 7.12.2. Классификация ошибок (summary). Для встроенного предиката arg/3 ошибки a, b, c, d следуют из спецификации. Только ошибка e не выполняется.

8.5.2.3 Ошибки

a) N - переменная — instantiation_error.

b) Term - переменная — instantiation_error.

c) N не является ни переменной, ни целым числом — type_error(integer, N).

d) Term не является ни переменной, ни составным термином
type_error(compound, Term).

e) N - целое число меньше нуля
domain_error(not_less_than_zero, N).

x.y.z.4 Примеры

(необязательно).

x.y.z.5 Загруженные встроенные предикаты

(необязательно). Определяет другие предикаты, которые настолько похожи, они могут быть "загружены".