Ответ 1
Давайте сначала привыкнем к декларативному чтению логических программ.
Декларативно программа Prolog устанавливает, что истинно.
Например
natural_number(0).
natural_number(s(X)) :-
natural_number(X).
В первом условии говорится: 0
- натуральное число.
Во втором разделе говорится: Если X
является натуральным числом, , то s(X)
является натуральным числом.
Давайте рассмотрим эффект изменений этой программы. Например, что меняется при изменении порядка этих двух статей?
natural_number(s(X)) :-
natural_number(X).
natural_number(0).
Декларативно, обмен порядком предложений не изменяет предполагаемого значения программы каким-либо образом (дизъюнкция является коммутативной).
Оперативно, то есть, принимая во внимание фактическую стратегию исполнения Prolog, разные заказы оговорки явно часто имеют значительную разницу.
Однако одно чрезвычайно приятное свойство чистого кода Prolog сохраняется независимо от выбранного порядка заказа:
Если запрос
Q
преуспевает в отношении порядка заказаO1
, тогдаQ
не прерывается с другим порядкомO2
.
Обратите внимание, что я не говорю, что Q
всегда также выполняется с другим порядком: это потому, что запрос может также зацикливаться или давать ошибку с разными порядками.
Для двух запросов Q1
и Q2
мы говорим, что G1
является более общим, если он включает G2
в отношении синтаксической унификации. Например, запрос ?- parent_child(P, C).
является более общим, чем запрос ?- parent_child(0, s(0)).
.
Теперь, с чистыми программами Prolog, выполняется еще одно чрезвычайно приятное свойство:
Если запрос
Q1
преуспевает, тогда все более общий запросQ2
не потерпеть неудачу.
Обратите внимание, что Q2
может зацикливаться вместо следующего.
Рассмотрим теперь случай var/1
, который вы упомянули, и подумайте о соответствующем предикате nonvar/1
. Предположим, что:
my_pred(V) :-
nonvar(V).
Когда это выполняется? Ясно, что это выполняется, если аргумент не является переменной.
Как и ожидалось, получаем:
?- my_pred(a).
true.
Однако для более общего запроса ?- my_pred(X).
получаем:
?- my_pred(X).
false.
Такой предикат называется немонотонным, и вы не можете рассматривать его как истинное отношение из-за этого свойства: это потому, что ответ false
выше логически означает, что нет никаких решений, но в предыдущем примере, мы видим, что существует решение. Таким образом, нелогично, более конкретный запрос, построенный путем добавления ограничения, делает запрос успешным:
?- X = a, my_pred(X).
true.
Таким образом, рассуждение о таких предикатах чрезвычайно сложно, до такой степени, что вообще не весело программировать с ними. Это делает декларативную отладку невозможной и трудно указать любые сохраненные свойства. Например, простое изменение порядка подцелей в вышеуказанном конъюнктивном запросе приведет к сбою:
?- my_pred(X), X = a.
false.
Следовательно, я настоятельно рекомендую оставаться в пределах чистого монотонного подмножества Prolog, что позволяет декларативно рассуждать по указанным выше строкам.
Ограничения CLP (FD), dif/2
и т.д. в этом смысле чисты: вы не можете обмануть эти предикаты в предоставлении логически недействительных ответов, независимо от режимов, заказов и т.д., в которых вы их используете. if_/3
также удовлетворяет этому свойству. С другой стороны, var/1
, nonvar/1
, integer/1
, !/0
, предикаты с побочными эффектами и т.д. Являются вседо логически ссылкой на что-то вне декларативного мира, который описывается, и поэтому его нельзя рассматривать чистый.
РЕДАКТИРОВАТЬ. Чтобы уточнить: полезные свойства, которые я упоминаю здесь, никоим образом не являются исчерпывающими. В коде Pure Prolog есть много других чрезвычайно ценных свойств, благодаря которым вы можете воспринимать славу логического программирования. Например, в чистом коде Prolog добавление предложения может в наибольшей степени расширить, не сузить набор решений; добавление цели может быть наиболее узким, никогда не расширяться, и т.д.
Использование одного экстра-логического примитива может и, как правило, уже уничтожить многие из этих свойств. Поэтому, например, каждый раз, когда вы используете !/0
, считайте его срезанным прямо в сердце чистоты и пытайтесь почувствовать сожаление и стыд за ранение этих свойств.
Хорошая книга Prolog, по крайней мере, начнет вводить или содержать много подсказок для поощрения такого декларативного представления, поможет вам подумать о более общих запросах, сохраняемых свойствах и т.д. Книги Bad Prolog не будут говорить об этом и, как правило, в конечном итоге, используя именно те нечистые языковые элементы, которые уничтожают язык, наиболее ценные и красивые свойства.
Удивительная среда обучения Prolog, которая широко использует эти свойства для реализации декларативной отладки, называется GUPU, я настоятельно рекомендую проверить эти идеи. Ульрих Ноймеркель щедро сделал одну основную идею, которая используется в его среде, частично доступной как библиотека (диадема). См. Исходный файл для хорошего примера о том, как декларативно отлаживать цель, которая неожиданно завершается: библиотека систематически строит обобщения запроса, который все еще терпит неудачу. Разумеется, это рассуждение отлично работает с чистым кодом.