Пролог Список Плато - PullRequest
       38

Пролог Список Плато

4 голосов
/ 13 марта 2012

Только что познакомился с прологом, пытаясь выполнить несколько простых упражнений, но я застрял на этом.Я пытаюсь написать программу, которая выводит все подсписки списка ввода, где каждый подсписок имеет длину> 1, и его нельзя расширить до большего подсписка.Также будет выведена начальная позиция в списке подсписка.Таким образом, пример вывода будет

| ?- plateau([a,a,b,2,2,2,a+1,a+1,s(1,2)], I, Len).
    I = 1,
    Len = 2 ? ;
    I = 4,
    Len = 3 ? ;
    I = 7,
    Len = 2 ? ;
    no

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

program([H|T],I,L):-
    T = [H1|T1] %split the tail
    ([H] = [H1] -> Count is Count+1, program(T,I,Count) 
     %if First element = second element, recurse with new values
    ; length(T,Spot), 
      %get the spot where you are in the list, so we know where sublist starts
      program(T,Spot,L) %run again, from tail, since sublist didn't have another  element?
program([],I,L). %terminate when entire list has been run through?

Так что это не работает, что я могу сказать по нескольким причинам.Я не сбрасываю 'count', так что это суммирует значения всех подсписков вместе?Есть ли способ обойти это?Мой базовый случай также может быть не тем, что я хочу - я просто не уверен, каким он должен быть на самом деле?Я, вероятно, скучаю по другим вещам ... любая помощь очень ценится:) Спасибо!

Ответы [ 5 ]

7 голосов
/ 13 марта 2012

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

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

seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).

Это чрезвычайно полезный нетерминал!

?- phrase((seq(Prefix),seq(Sublist),seq(Postfix)),
      [a,a,b,2,2,2,a+1,a+1,s(1,2)]).
Prefix = Sublist, <strong>Sublist = []</strong>,
Postfix = [a,a,b,2,2,2,a+1,a+1,s(1,2)] ;
Prefix = [],
Sublist = <strong>"a"</strong>,
Postfix = [a,b,2,2,2,a+1,a+1,s(1,2)] ...

Оба ответа не ожидаются, нам нужны только подспискидлина 2 или больше, поэтому мы должны немного ограничить это определение.Скажем, требуя, чтобы Sublist содержал как минимум два элемента.Это Sublist = [_,_|_].

?- Sublist = [_,_|_],
   phrase((seq(Prefix),seq(Sublist),seq(Postfix)),
      [a,a,b,2,2,2,a+1,a+1,s(1,2)]).
Sublist = "aa",
Prefix = [],
Postfix = [b,2,2,2,a+1,a+1,s(1,2)] ;
<strong>Sublist = "aab"</strong>,
Prefix = [],
Postfix = [2,2,2,a+1,a+1,s(1,2)] ...

Первый ответ показывает список, который мы ищем.Но второе все равно неверно: все элементы подсписка должны быть равны.Самый простой способ - использовать maplist/2:

?- maplist(=(_),Es).
Es = [] ;
Es = [_G221] ;
Es = [_G221,_G221] ;
Es = [_G221,_G221,_G221] 

Есть несколько мест, где мы могли бы заявить это требование.Я поставлю его как можно раньше:

?- Sublist = [_,_|_],
        phrase(( seq(Prefix),
                 seq(Sublist),{maplist(=(_),Sublist)},
                 seq(Postfix)),
           [a,a,b,2,2,2,a+1,a+1,s(1,2)]).
Sublist = "aa",
Prefix = [],
Postfix = [b,2,2,2,a+1,a+1,s(1,2)] ;
<strong>Sublist = [2,2]</strong>,
Prefix = "aab",
Postfix = [2,a+1,a+1,s(1,2)] ;
Sublist = [2,2,2],
Prefix = "aab",
Postfix = [a+1,a+1,s(1,2)] ;
<strong>Sublist = [2,2]</strong>,
Prefix = [a,a,b,2],
Postfix = [a+1,a+1,s(1,2)] ;
Sublist = [a+1,a+1],
Prefix = [a,a,b,2,2,2],
Postfix = [s(1,2)] ;
false.

Так что теперь все подсписки содержат идентичные элементы.Увы, мы получаем [2,2] и [2,2,2] в качестве подсписка.Нам нужен только максимальный подсписок.Итак, как мы можем описать, что такое максимальный подсписок?

Один из способов - посмотреть перед нашим подсписком: не должно быть одного и того же элемента нашего подсписка.Таким образом, либо впереди ничего (эпсилон), либо последовательность, которая заканчивается элементом, отличным от нашего.

difel(_E,[]).
difel(E, Es) :- dif(E,F), phrase((seq(_), [F]), Es).
?- Sublist = [_,_|_],
   phrase(( seq(Prefix),{difel(E,Prefix)},
            seq(Sublist),{maplist(=(E),Sublist)},
            seq(Postfix)),
      [a,a,b,2,2,2,a+1,a+1,s(1,2)]).
Sublist = "aa",
Prefix = [],
E = a,
Postfix = [b,2,2,2,a+1,a+1,s(1,2)] ;
Sublist = [2,2],
Prefix = "aab",
E = 2,
Postfix = [2,a+1,a+1,s(1,2)] ;
Sublist = [2,2,2],
Prefix = "aab",
E = 2,
Postfix = [a+1,a+1,s(1,2)] ;
Sublist = [a+1,a+1],
Prefix = [a,a,b,2,2,2],
E = a+1,
Postfix = [s(1,2)] ;
false.

Один неверный ответ меньше.В конце все еще таится один.

?- Sublist = [_,_|_],
   phrase(( seq(Prefix),{difel(E,Prefix)},
            seq(Sublist),{maplist(=(E),Sublist)},
            ( [] | [F],{dif(E,F)},seq(_) ) ),
      [a,a,b,2,2,2,a+1,a+1,s(1,2)]).
Sublist = "aa",
Prefix = [],
E = a,
F = b ;
Sublist = [2,2,2],
Prefix = "aab",
E = 2,
F = a+1 ;
Sublist = [a+1,a+1],
Prefix = [a,a,b,2,2,2],
E = a+1,
F = s(1,2) ;
false.

Это не совсем то, что вы хотели: вы просто хотели длины.Для этого добавьте length([_|Prefix],I), length(Sublist,Len).

Итак, вот окончательное определение:

plateau(Xs, I, Len) :-
   Sublist = [_,_|_],
   phrase(( seq(Prefix),{difel(E,Prefix)},
            seq(Sublist),{maplist(=(E),Sublist)},
            ( [] | [F],{dif(E,F)},seq(_) ) ),
      Xs),
   length([_|Prefix],I),
   length(Sublist,Len).
2 голосов
/ 16 марта 2012

Здесь довольно много сложных ответов.Рассмотрим тот, который не использует DCG или многие встроенные модули (возможно, проще для новичка):

plateau([X|Xs], I, L) :-
    plateau(Xs, 1-1-X, I, L).

plateau([X1|Xs], I0-L0-X0, I, L) :-
    X0 == X1, !,
    NL0 is L0 + 1,
    plateau(Xs, I0-NL0-X0, I, L).

plateau(_, I-L-_, I, L) :-
    L > 1.

plateau([X|Xs], I0-L0-_, I, L) :-
    NI is I0 + L0,
    plateau(Xs, NI-1-X, I, L).

Первое предложение устанавливает вызов, который накапливает (index) - (length) - (sublist element) кортеж, как термин.

Следующее предложение увеличивает length, если следующий список element такой же (обратите внимание, что индекс не был изменен).

Третье предложение вызывается, только если второе предложение не выполнено при тестировании, если прогон элемента подсписка был прерван (из-за сокращения !), и возвращает решение, если length прогона было > 1.

Последнее предложение позволяет Прологу вернуться назад и перезапустить поиск с последнего запуска.

РЕДАКТИРОВАТЬ: Решение gusbro на самом деле очень близко к этому ...+ 1.

1 голос
/ 16 марта 2012

Это просто и понятно. Мы считаем от 1; плато - максимальная подпоследовательность равных элементов длиной не менее 2; мы продолжаем список. Просто запишите это:

plateau(L,I,N):- plateau(L,1,I,N).                     % count from 1

plateau([A,A|B],I1,I,N):- !, more_elts(A,B,2,K,C),     % two equals, or more
    (I is I1, N is K ; plateau(C,I1+K,I,N)).
plateau([_|B],I1,I,N):- plateau(B,I1+1,I,N).           % move along the list

more_elts(A,[A|B],I,K,C):- !, more_elts(A,B,I+1,K,C).
more_elts(_,B,I,I,B).

обновление: Предполагается, что все элементы списка ввода nonvar/1. Наличие здесь неинстанцированных переменных в качестве элементов входного списка делает понятие «подсписок» хитрым и расплывчатым. Например, каковы подсписки [a,X,b,b]? Могут ли [a,a] и [b,b,b] оба быть подсписками списка ввода того же ? (это мне как-то напоминает наблюдаемые значения спина, суперпозиции состояний и т. Д. ... Когда выбрано направление наблюдения спина, его уже нельзя изменить ... см. Все разговоры об «измерении» и квантовая механика в sokuza-kanren.scm (обнаружил, что ссылка здесь ))

1 голос
/ 13 марта 2012

Я пытался использовать nth1 / 3 встроенный, но у меня было больше проблем, чтобы заставить его работать ... в любом случае, здесь другая реализация:

plateau(L, I, Len) :-
    plateau(L, 1, I, Len).
plateau(L, P, I, Len) :-
    nth1(P, L, E),
    skipseq(P, L, E, J),
    (   J > P,
        Len is J - P + 1,
        I is P
    ;   Q is J + 1,
        plateau(L, Q, I, Len)
    ).

% get the index J of last element E (after I)
skipseq(I, L, E, J) :-
    T is I + 1,
    nth1(T, L, E),
    !, skipseq(T, L, E, J).
skipseq(I, _, _, I).

test:

[debug]  ?- plateau([a,x,x,x,u,u,h,w],I,N).
I = 2,
N = 3 ;
I = 5,
N = 2 ;
false.
1 голос
/ 13 марта 2012

Вы можете сделать что-то вроде этого:

plateau([Item|Tail], I, Len):-
  plateau(Tail, 1, Item, 1, I, Len).

plateau(List, From, NItem, Len, From, Len):-
  (List=[Item|_] -> (Item\=NItem;var(Item)); List = []),
  Len > 1.
plateau([Item|Tail], IFrom, Item, ILen, From, Len):-
  MLen is ILen + 1,
  plateau(Tail, IFrom, Item, MLen, From, Len).
plateau([Item|Tail], IFrom, OItem, ILen, From, Len):-
  OItem \= Item,
  NFrom is IFrom + ILen,
  plateau(Tail, NFrom, Item, 1, From, Len).

Первый пункт плато / 6 касается прекращения подсписка. Это либо случай, когда предмет отличается от того, который вы ищете, либо вы достигли конца списка. В этом случае мы продолжаем, только если текущая длина больше единицы.

Второе предложение касается шага рекурсии для случая, когда мы все еще сопоставляем элемент в списке. Он просто добавляет один к счетчику текущего подсписка и выполняет рекурсию.

Последнее предложение касается случая нового (другого) элемента, найденного в списке, и просто сбрасывает счетчики и выполняет рекурсию.

...