Пролог - как проверить, содержит ли список определенные элементы? - PullRequest
8 голосов
/ 04 марта 2011

Я пробую Пролог в первый раз и испытываю небольшие трудности с использованием списков.

Скажем, у меня есть список элементов.Я хочу убедиться, что в списке есть следующие элементы:

Все: A1, A2, A3, A4, A5

Один из: B1, B2, B3, B4

Два из: C1, C2, C3, C4, C5, C6

Например, [A1, A2, B2, C1, A3, A4, C4, A5] соответствует требованиям и [A2, A1, C1, B1, A3, A4] - нет.

Как я могу написать что-то, что возвращает Да / Правда, если список соответствует требованиям, и Нет / Ложь в противном случае?Точно так же, как насчет записи чего-то, что возвращает отсутствующие значения из списка, необходимого для удовлетворения требований?

1 Ответ

19 голосов
/ 04 марта 2011

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

Сначала рассмотрим случай проверки того, что все записи одного списка также находятся в другом списке:

subset([ ],_).
subset([H|T],List) :-
    member(H,List),
    subset(T,List).

Эта простая рекурсия использует знакомый предикат member / 2 для проверки каждой записи в списке, заданном первым аргументом subset / 2 , также в списке, заданном вторым аргументом,[Для простоты я предположил, что записи в этом списке различны.Более сложная версия была бы необходима, если бы мы хотели проверить, совпадают ли несколько экземпляров записи первого списка как минимум с тем количеством экземпляров во втором списке.]

Хорошо, как насчет проверки этого (вминимум) один из первого списка принадлежит также ко второму списку?Очевидно, что это предикат, отличный от приведенного выше.Вместо всех элементов в первом списке цель должна быть достигнута, если существует любой элемент в первом списке, который принадлежит второму списку.

intersects([H|_],List) :-
    member(H,List),
    !.
intersects([_|T],List) :-
    intersects(T,List).

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

Что если мы хотим обобщить эту проверку, чтобы проверить (как минимум) N элементов первого списка во втором?Получившемуся предикату потребуется третий аргумент:

intersectsAtLeast(_,_,N) :- N <= 0, !.
intersectsAtLeast([H|T],L,N) :-
    member(H,L),
    !,
    M is N-1,
    intersectsAtLeast(T,L,M).
intersectsAtLeast([_|T],L,N) :-
    intersectsAtLeast(T,L,N).

Эта рекурсия работает по списку, уменьшая третий аргумент на единицу каждый раз, когда элемент из первого списка также оказывается во втором списке,и успешно, как только счет уменьшается до 0 (или меньше).[Опять же, код здесь требует доработки, если списки могут иметь повторы.]

Наконец, вы спрашиваете о написании чего-то, что «возвращает пропущенные значения», должно соответствовать требованиям.Это не очень хорошо определено в случае проверки одного или нескольких элементов в обоих списках, поскольку «отсутствующее значение» может быть любым из нескольких возможных элементов.В особом случае, когда мы попросили, чтобы все элементы первого списка принадлежали второму списку, можно определить «пропущенные значения» (если они есть).

missingValues([ ],_,[ ]).
missingValues([H|T],L,K) :-
    member(H,L),
    !,
    missingValues(T,L,K).
missingValues([H|T],L,[H|K]) :-
    missingValues(T,L,K).

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

Последнее замечание по вашим вопросам касается записи.В прологе переменные - это идентификаторы, которые начинаются с заглавной буквы или знака подчеркивания, поэтому использование A1, A2 и т. Д. В качестве элементов в списке может привести к проблемам, если они рассматриваются как «неизвестные», а не (как я полагаю, вы имели в виду) отдельные атомы (константы).Переключение на строчные буквы решит это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...