Подтвердить что ты не робот

Prolog - Поиск смежных элементов в списке

Я пытаюсь определить предикат adjacent(X, Y, Zs), который является истинным, если X и Y смежны в списке. Мой код в настоящее время:

adjacent(_, _, []).
adjacent(X, Y, [X, Y|Tail]) :-
  adjacent(X,Y, Tail).

Он работает для основного случая adjacent(c, d, [a, b, c, d, e]), но из-за базового случая каждый другой случай также возвращает true, и я застрял на этом.

Другая проблема заключается в том, что если X не равно первой части списка, то она пропускает мимо X и Y и переходит к следующему "X"; например, если c не равно a, то он пропускает как a, так и b и проверяет, c равно c. Это проблематично, если, например, список

[a, c, d, e]

потому что он никогда не проверяет c (я считаю).

Я довольно потерял, как примирить эти два вопроса и повернуть свое логическое понимание того, что должно произойти в коде.

РЕДАКТИРОВАТЬ: Благодаря ответу Христиана Худжера моя ошибка базового случая была исправлена, так что теперь я просто застрял во второй проблеме.

4b9b3361

Ответ 1

В исходной попытке решения:

adjacent(_, _, []).
adjacent(X, Y, [X, Y|Tail]) :-
    adjacent(X,Y, Tail).

Как указывает @ChristianHujer, первое предложение не должно быть там, потому что это неверно. В пустом списке не должно быть смежных элементов.

Второе предложение также проблематично. Он показывает, что X и Y смежны в списке, но затем повторяются и не просто преуспевают. Правильное предложение должно быть:

adjacent(X, Y, [X,Y|_]).

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

adjacent(X, Y, [_|Tail]) :-
    adjacent(X, Y, Tail).

Это говорит о том, что X и Y смежны в [_|Tail], если они смежны в Tail. Это позаботится о второй проблеме, с которой вы столкнулись.

Таким образом, все решение будет:

adjacent(X, Y, [X,Y|_]).
adjacent(X, Y, [_|Tail]) :-
    adjacent(X, Y, Tail).

Это будет выполняться столько раз, сколько X и Y отображаются вместе, в указанном порядке, в списке.


Это также естественно разрешимо с помощью DCG (хотя решение @repeat append/3 является более кратким):
adjacent(X, Y) --> ..., [X, Y], ... .
... --> [] | [_], ... .

adjacent(X, Y, L) :- phrase(adjacent(X, Y), L).

| ?- adjacent(b, c, [a,b,c,d]).

true ? a

(1 ms) no
| ?- 

Ответ 2

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

Ответ 3

В этом ответе мы стараемся сохранить его простым: построив append/3:

<Предварительно > смежные (E0, E1, Es): -   append (_, [E0, E1 | _], Es).

Пример запроса:

?- adjacent(X, Y, [a,b,c,d,e]).
X = a, Y = b ;
X = b, Y = c ;
X = c, Y = d ;
X = d, Y = e ;
false.

Ответ 4

Вспомогательный предикат adjacent_/5 всегда "отстает" ровно двумя (элементами списка):

<Предварительно > смежные (X0, X1, [E0, E1 | Es]): -  adj_ (Es, E0, E1, X0, X1). смежные _ ([], E0, E1, E0, E1). смежный _ ([E2 | Es], E0, E1, X0, X1): -  if_ (E0 + E1 = X0 + X1,      правда,      смежные_ (Es, E1, E2, X0, X1)).

Используя SWI-Prolog, мы запускаем:

<Предварительно > ? - set_prolog_flag (double_quotes, chars). правда. ? - соседний (a, b, "abab" ). правда. ? - смежные (b, c, "abcd" ). правда. ? - смежные (X, Y, "abcd" ).  X = a, Y = b ; X = b, Y = c ; X = c, Y = d.

Изменить

Исправленное определение adjacent_/5 дает правильные ответы на следующие запросы:

?- adjacent(X, X, [A,B,C]).
   X = A, A = B
;  X = B, B = C, dif(f(C,C),f(A,A)).

?- adjacent(a, X, "aab").
   X = a
;  X = b.

?- adjacent(a, b, "aab").
true.

Ответ 5

Вот определение, которое, по моему мнению, в долгосрочной перспективе предпочтительнее для решения @repeat:

adjacent(X0, X1, [E0,E1|Es]) :-
   adjacent_(Es, E0, E1, X0, X1).

adjacent_([],      E0, E1, E0, E1).
adjacent_([E2|Es], E0, E1, X0, X1) :-
   if_(( E0 = X0, E1 = X1 ),
       true,
       adjacent_(Es, E1, E2, X0, X1)).

Используя reified и:

','(A_1, B_1, T) :-
   if_(A_1, call(B_1, T), T = false).

;(A_1, B_1, T) :-
   if_(A_1, T = true, call(B_1, T)).