Проблема пролога с функцией максимального списка: недетерминированная и противодействующая процедура
Я пытаюсь сделать небольшой проект в прологе, где пользователь может ввести список, а затем он вычисляет среднее значение, максимум в списке и т. Д. И т. Д.
Пока все хорошо, но я столкнулся с проблемой при написании функции 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).