Проблема пролога с функцией максимального списка: недетерминированная и противодействующая процедура

Я пытаюсь сделать небольшой проект в прологе, где пользователь может ввести список, а затем он вычисляет среднее значение, максимум в списке и т. Д. И т. Д.

Пока все хорошо, но я столкнулся с проблемой при написании функции max (находит максимальное число в списке). Код является:

maxN([X],X):-!.
maxN([X|L],X) :- maxN(L,M), X > M.
maxN([X|L],M) :- maxN(L,M), M >= X.

Сама функция работает отдельно, но я получаю это сообщение об ошибке:

Предикат 'forma::maxN/2 (i,o)', который объявлен как 'процедура', на самом деле является 'недетерминированным' forma.pro

Это мой предикат в определении *.cl:

maxN: (целое число * Z, целое число U) процедура (i,o).

Я не могу объявить его недетерминированным, потому что это вызывает проблемы со всей моей формой. Можете ли вы помочь мне / дать подсказку, как сделать процедуру? Я думаю, что должен где-то сделать разрез, но мои попытки пока не увенчались успехом.

PS Я использую Visual Prolog 7.4.

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

2 ответа

Решение

Проблема в том, что Пролог видит точку выбора между вашими вторыми и третьими правилами. Другими словами, вы, человек, знаете, что оба X > M а также M >= X оба не могут быть правдой, но Пролог не в состоянии сделать это.

ИМО лучше всего было бы перефразировать эти два правила одним правилом:

maxN([X], X) :- !.
maxN([X|L], Max) :- 
   maxN(L, M), 
   X > M -> Max = X
          ; Max = M.

Таким образом, никогда не будет лишней точки выбора, которую нужно было бы обрезать срезом.

Следуя совету @CapelliC, вы также можете переформулировать это с помощью аккумулятора:

maxN([X|Xs], Max) :- maxN_loop(Xs, X, Max).

maxN_loop([], Max, Max).
maxN_loop([X|Xs], Y, Max) :- 
   X > Y -> maxN_loop(Xs, X, Max)
          ; maxN_loop(Xs, Y, Max).

Извините, я не знаю, какой диалект пролога вы используете, мой совет: попробуйте добавить вырезку после второго предложения:

maxN([X|L],X) :- maxN(L,M), X > M, !.

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

maxN([],A,A).
maxN([X|L],A,M) :- X > A, !, maxN(L,X,M).
maxN([X|L],A,M) :- maxN(L,A,M).

Конечно, вызов на высшем уровне должен стать

maxN([F|L],M) :- maxN(L,F,M).
Другие вопросы по тегам