Пролог: вычет, учитывая, что предметы могут быть в одном из двух наборов, с известными размерами набора

У меня есть 5 человек в комнате. Я напишу правила, чтобы определить, счастливы ли люди или грустны. Однако, прежде чем я начну с этого, я знаю, что из 5 - ровно 3 - счастливы, а 2 - грустны (и ни один не может быть и тем, и другим). Следовательно, должна быть возможность сделать выводы на основе этого: если - каким-либо образом - я знаю, кто эти три счастливых человека, то я могу вывести двух печальных людей, и наоборот.

То, что я получил до сих пор, таково:

person(bob).
person(tim).
person(steve).
person(roy).
person(jack).

sad(bob).
sad(tim).

happy(X) :-
  person(X),
  \+ sad(X),
  findall(Y, sad(Y), YS),
  length(YS, 2).

Когда спросили happy(X)Пролог даст мне Роя, Стива и Джека, потому что он уже знает, кто эти два печальных человека. Проблема: я не могу определить sad/1 править таким же образом, из-за взаимной рекурсии с happy/1, Я хочу иметь возможность добавлять в правила, чтобы результат в приведенном выше примере оставался прежним, но при следующей инициализации Боб и Тим отобразились бы как грустные:

person(bob).
person(tim).
person(steve).
person(roy).
person(jack).

happy(steve).
happy(roy).
happy(jack).

Есть ли лучший способ, которым я должен думать об этом? Важно, что я смогу позже написать больше правил для sad/1 а также happy/1добавив дополнительную логику помимо того факта, что вычет должен быть возможен на основе знания того, что 5 делятся на 3 счастливых и 2 печальных.

2 ответа

Как насчет использования clpb?

: - use_module( библиотека (clpb)).

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

? - Hs = [Боб, Тим, Стив, Рой, Джек],
   сб (карточка ([3], хз)),                               % ровно три счастливы.
   (Кто = грустный, сидел (~H_bob * ~H_tim)             % указывает грустные...; Кто = счастлив, сидел (H_jack * H_roy * H_steve)    %  ... ИЛИ счастливые?),
   маркировка (Hs).
   Кто = грустный, Боб = 0, Тим = 0, Джек = 1, Рой = 1, Стив = 1, Hs = [0,0,1,1,1]; Кто = счастлив, Боб = 0, Тим = 0, Джек = 1, Рой = 1, Стив = 1, Hs = [0,0,1,1,1].

Сортировка логики - это вопрос последовательности и избегания противоречивых значений данного предиката или факта.

Ваше определение sad/1 в настоящее время факт, который приводит к одному результату для каждого возврата к запросу, sad(X), Но ваше определение happy/1 генерирует список. Это оставляет вас с тем, как вы хотите определить sad/1 создать список, который будет противоречить вашему текущему определению sad/1 как запрос, который является истинным, если аргумент грустный человек.

Более последовательный подход будет определять happy/1 вести себя так, как надо sad/1 ведет себя:

happy(X) :-
    person(X),
    \+ sad(X).

Затем вы можете определить свой список версий:

happy_all(A) :-
    findall(X, happy(X), A).

sad_all(A) :-
    findall(X, sad(X), A).

Теперь вышесказанное предполагает, что у вас есть явные факты для person/1 которая определяет вселенную всех действительных людей, и sad/1 который определяет, кто грустный. Это также предполагает, что если человек не грустит, то он должен быть счастлив.

Вы можете перевернуть это и явно определить счастливых людей с happy/1 факты, а затем определить sad/1 с точки зрения людей, которые не счастливы, полагая, что человек должен быть счастлив, если ему не грустно:

sad(X) :-
    person(X),
    \+ sad(X).

И happy_all/1 а также sad_all/1 предикаты все еще будут применяться.

Если вы хотите смешать ваши факты с happy/1 а также sad/1, это может создать проблему согласованности: (1) случаи, когда человек не определен как счастливый или грустный... тогда кто они? и (2) что если человек определяется как счастливый и грустный?

Семантически, вы можете определить оба sad/1 а также happy/1 явно, если вы также допускаете, чтобы кто-то не был ни счастливым, ни грустным. Вы можете сделать это:

person(bob).
person(tim).
person(steve).
person(roy).
person(jack).

sad(bob).
sad(tim).

happy(steve).
happy(roy).

happy_all(A) :-
    findall(X, happy(X), A).

sad_all(A) :-
    findall(X, sad(X), A).

Но не определять предикаты для happy/1 или же sad/1 так как они уже факты. Это делает вещи простыми. Мы просто не знаем, если jack счастлив или грустен.

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

person(bob).
person(tim).
person(steve).
person(roy).
person(jack).

sad(bob).
sad(tim).

happy(steve).
happy(roy).

% A person is happy if they are, in fact, happy
happy_person(X) :-
    happy(X),
% A person is happy if they are neither happy or sad
happy_person(X) :-
    person(X),
    \+ happy(X),
    \+ sad(X).

% A person is sad if they are, in fact, sad
sad_person(X) :-
    sad(X).

% Who are all the happy people?
happy_all(A) :-
    findall(X, happy_person(X), A).

% Who are all the sad people?
sad_all(A) :-
    findall(X, sad_person(X), A).
Другие вопросы по тегам