Поиск запроса, для которого программа на прологе дает неверный результат

Эта программа на Прологе определяет третий аргумент как максимальное значение первых двух числовых аргументов:

max(X, Y, X) :- X >= Y, !.
max(X, Y, Y).

Я думаю, что эта программа работает просто отлично. Но мне сказали, что это может дать неверный результат. Можете ли вы сказать, когда и почему?


person Rayhunter    schedule 15.05.2013    source источник
comment
Что, если X,Y не связаны с целыми или действительными числами?   -  person hardmath    schedule 16.05.2013
comment
мы предполагаем, что аргументы являются числовыми значениями   -  person Rayhunter    schedule 16.05.2013


Ответы (2)


Это пример из учебника.

?- max(5,1,1).
true.

Домашнее задание: Почему программа неверна? Как сделать программу корректной?

ИЗМЕНИТЬ

max(X, Y, X) :- X >= Y, !.
max(X, Y, Y).

Наше намерение состоит в том, чтобы сказать:

Если X больше Y, тогда Max равен X. В противном случае Max должен быть Y.

Вместо этого говорят:

Когда первый и третий аргументы (X и Max) могут быть объединены, а X больше Y, успех. В противном случае, если второй и третий аргументы (Y и Max) могут быть объединены, успешно.

Возникает очевидная проблема, когда первый и третий аргументы нельзя объединить, а второй и третий можно.

Вместо:

max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- X < Y.

or

max(X, Y, Max) :- X >= Y, !, Max = X.
max(_, Max, Max).
person Community    schedule 15.05.2013
comment
Это определение max/3 работает только в том случае, если все аргументы созданы. Однако, как правило, нужно не только тестировать, но и находить решения, например, каково максимальное из двух заданных чисел? Или, например, какие числа имеют заданный максимум? Современным решением таких вопросов являются ограничения, например, с ограничениями конечной области: M #= max(X, Y). Его можно использовать во всех направлениях, для поиска и проверки решений. - person mat; 16.05.2013
comment
@мат Абсолютно. Но это, в конце концов, явный случай экзаменационного/учебного вопроса и, очевидно, следует ответу из учебника. Я бы хотел, чтобы люди читали хотя бы The Art of Prolog, когда они будут проходить курс в университете, и обсуждения Stackoverflow наконец-то смогут перейти от вопросов, ответы на которые были даны несколько десятилетий назад, на более зеленое пастбище. К сожалению, этого не происходит, и тег Пролога завален непродуктивным пережевыванием векового засохшего хлама. - person ; 16.05.2013
comment
@mat не все, но, по крайней мере, первые два. Если вы используете нотацию SWI-Prolog, это будет max(+A, +B, -Max) - person ; 16.05.2013

Это работает нормально, если третий аргумент не конкретизирован. Опасность здесь была бы в том случае, если бы был способ вернуться ко второму правилу или если бы третьему аргументу присваивалось то же значение, что и второму. Это не особенно безопасно, потому что max(X, Y, Y). равно max(_, Y, Y), что просто устанавливает результат на второе значение без каких-либо размышлений. Сокращение в конце первого правила эффективно гарантирует, что поиск с возвратом не начнется, если X >= Y, поэтому второе правило следует вводить только тогда, когда X ‹ Y и Z еще не равно Y.

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

max(X, Y, X) :- X >= Y.
max(X, Y, Y) :- X < Y.

or

max(X, Y, Z) :- X >= Y -> Z = X ; Z = Y.

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

max(X, Y, X) :- X >= Y, !.
max(X, Y, Y) :- X < Y.

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

К сожалению, указание условия дважды кажется излишним, но полагаться на одно правило кажется неуклюжим. На практике мой опыт показывает, что подобные сценарии не так уж и распространены; обычно у вас есть атомы или структуры, которые вы можете сопоставить в заголовке предложения, которые создают поведение, подобное тому, которое мы имеем в моем первом заместителе, но без необходимости в теле. Например:

perform(scan(target, X, Y)) :- ...
perform(scan(calibration, X)) :- ...

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

person Daniel Lyons    schedule 15.05.2013
comment
Ваши рассуждения в первом абзаце неверны. Когда второй и третий аргументы приводятся к одному и тому же номеру, первое предложение вообще не рассматривается. - person ; 16.05.2013
comment
Но зачем вам создавать экземпляр третьего аргумента для меньшего числа из двух, если вы хотите, чтобы оно было большим? - person Rayhunter; 16.05.2013
comment
@Борис Хороший звонок. Починю. - person Daniel Lyons; 16.05.2013