Печать минимального ответа в виде списка?

#prolog

#пролог

Вопрос:

У меня есть предикат min1([4,2,3,5],L). Я хочу, чтобы он возвращал минимальное число для каждого раза, когда список отправляется обратно в виде хвоста. Пример:

 List       Head|Tail    Tail     L
[4,2,3,5]  [4,2,3,5]    [2,3,5]  2
[2,3,5]    [2,3,5]      [3,5]    2
[3,5]      [3,5]        [5]      3
[5]        [5]          []       5
 

Мой код:

 min([X],[X]).
min([H|T],Min):-
    min(T,TMin),
    H=<TMin,
    Min is H.
min([H|T],Min):-
    min(T,TMin),
    H>TMin,
    Min is TMin.

min1([],[]).
min1([H|T],L):-
  min([H|T],R),
    write(R),
    min1(T,R). 
 

Проблема, с которой я сталкиваюсь, связана с L. Он ничего не печатает. Когда я использую write (R), он показывает мне правильный результат, но я не могу распечатать его в виде списка в L. Что я должен исправить?

 ?-min1([4,2,3,5],L).
223[5]
L = []
 

Путем удаления write(R):

 ?-min1([4,2,3,5],L).
false
 

Ответ №1:

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

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

Итак, сначала: перечисление суффиксов списка (включая сам список как тривиальный суффикс).

 list_suffix(List, List).
list_suffix([_ | Suffix], SuffixOfSuffix) :-
    list_suffix(Suffix, SuffixOfSuffix).

?- list_suffix([4, 2, 3, 5], Suffix).
Suffix = [4, 2, 3, 5] ;
Suffix = [2, 3, 5] ;
Suffix = [3, 5] ;
Suffix = [5] ;
Suffix = [].
 

Затем, отдельно, вычисляем минимум списка. Ваша реализация почти подходит для этого, первое предложение необходимо развернуть [X] (хотя это могло бы быть более эффективным при использовании аккумулятора):

 list_minimum([X], X).
list_minimum([H | T], Min):-
    list_minimum(T, TMin),
    H =< TMin,
    Min is H.
list_minimum([H | T], Min):-
    list_minimum(T, TMin),
    H > TMin,
    Min is TMin.

?- list_minimum([4, 2, 3, 5], Minimum).
Minimum = 2 ;
false.
 

Теперь, и только сейчас, мы в состоянии решить объединенную проблему:

 ?- list_suffix([4, 2, 3, 5], Suffix), list_minimum(Suffix, Minimum).
Suffix = [4, 2, 3, 5],
Minimum = 2 ;
Suffix = [2, 3, 5],
Minimum = 2 ;
Suffix = [3, 5],
Minimum = 3 ;
Suffix = [5],
Minimum = 5 ;
false.
 

Вы можете упаковать это в определение предиката:

 list_suffix_suffixminimum(List, Suffix, SuffixMinimum) :-
    list_suffix(List, Suffix),
    list_minimum(Suffix, SuffixMinimum).

?- list_suffix_suffixminimum([4, 2, 3, 5], Suffix, SuffixMinimum).
Suffix = [4, 2, 3, 5],
SuffixMinimum = 2 ;
Suffix = [2, 3, 5],
SuffixMinimum = 2 ;
Suffix = [3, 5],
SuffixMinimum = 3 ;
Suffix = [5],
SuffixMinimum = 5 ;
false.
 

Может быть, даже без указания суффикса:

 list_suffixminimum(List, SuffixMinimum) :-
    list_suffix(List, Suffix),
    list_minimum(Suffix, SuffixMinimum).

?- list_suffixminimum([4, 2, 3, 5], SuffixMinimum).
SuffixMinimum = 2 ;
SuffixMinimum = 2 ;
SuffixMinimum = 3 ;
SuffixMinimum = 5 ;
false.
 

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

Комментарии:

1. Спасибо за подробный ответ. Можете ли вы объяснить мне одну маленькую вещь list_suffix(список, список). почему список, список в базовом варианте?

2. Потому что из ваших примеров выглядело так, как будто вы хотели последовательность 2, 2, 3, 5. Вы получаете 2 только дважды, если вы также рассматриваете сам список как его суффикс, поэтому, как только вы вычисляете минимум [4, 2, 3, 5] , чтобы получить 2, тогда и минимум [2, 3, 5] , чтобы получить 2.