Унификация (?) в Прологе

У меня есть школьный проект, где я должен работать с Prolog. Это все новое для меня, поэтому у меня есть некоторые проблемы.

У меня есть такой список:

List = [(_,_,_),(_,_,_),(_,_,_)]

Я должен получить от ввода информацию о каждом члене, через несколько предикатов, которые я должен создать.

Один из них типа:

predicate(M1,M2,M3, List)

и он говорит, что M1 является либо M2, либо M3, но не тем и другим одновременно. Например,

predicate((_,a,_),(2,_,_),(3,_,_),List)

утверждает, что член с «а» имеет либо 2, либо 3 в первом поле.

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

Я пробовал это:

predicate(M1,M2,M3,[_]) :- (M1=M2), not(M1=M3).
predicate(M1,M2,M3,[_]) :- (M1=M3), not(M1=M2).

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

Любая подсказка приветствуется. Спасибо!

РЕДАКТИРОВАТЬ:

Пример:

person(name,age,job).
List = [(einstein,_,_),_,_].

Итак, теперь у меня есть список из 3 человек, с Эйнштейном на первой позиции.

predicate = ((einstein,_,_),(_,87,_),(_,23,_), List).

List = [(einstein,87,_),_,_)];
List = [(einstein,23,_),_,_)].

Выше приведены 2 допустимых списка после применения предиката.

Это должна быть простая проблема, но я не могу понять это.

Спасибо!


person bex91    schedule 16.05.2013    source источник
comment
Ну, я попытался объяснить это в вопросе. Не уверен, что еще добавить. Предполагается, что предикат получает свойства о 3 элементах списка, что означает, что первый будет таким же, как один из двух других. (hifen — это подчеркивание, здесь его писать нельзя) predicate((einstein,-,-),(-,32,-),(-,45,-),List) означает, что эйнштейну будет либо 32, либо 45 лет, например.   -  person bex91    schedule 17.05.2013
comment
отредактировано :) Надеюсь, теперь стало понятнее.   -  person bex91    schedule 17.05.2013
comment
Извините, я не видел этот вопрос. Я искал, но не заметил. Я считаю, что это относится к моей проблеме. Я постараюсь выжать из этого максимум. Спасибо!   -  person bex91    schedule 17.05.2013
comment
нет проблем, здесь это довольно стандартно…   -  person Daniel Lyons    schedule 17.05.2013


Ответы (3)


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

predicate(M1, M2, M3, [M1, M2, M3]) :-
    M1 = M2, M1 \= M3
  ; M1 = M3, M1 \= M2.

EDIT: после комментариев

predicate(M1, M2, M3, List) :-
    member(M1, List),
    ( M1 = M2, M1 \= M3 ; M1 = M3, M1 \= M2 ).

Member/2 — это самое основное отношение в Прологе между списком и его элементами. Здесь показана способность базового движка связывать переменные при поиске решения.

Ваши данные дают

?- predicate((einstein,_,_),(_,87,_),(_,23,_), [E]).
E = (einstein, 87, _G3908) ;
E = (einstein, 23, _G3908).
person CapelliC    schedule 17.05.2013
comment
Спасибо за вашу помощь, но я не думаю, что объяснил себя должным образом. Извиняюсь. Предполагается, что M2 и M3 не входят в список, в котором находится M1. Я отредактировал вопрос, и я думаю, что теперь это понятно: D - person bex91; 17.05.2013
comment
Спасибо еще раз. Я протестировал этот код, и результат все еще не идеален, но приближается к нему. Я получил это: E = [(einstein, 87, _G824), _G832, _G835] ; E = [(эйнштейн, 23, _G824), _G832, _G835] ; E = [(эйнштейн, _G823, _G824), (эйнштейн, 87, _G842), _G835] ; E = [(эйнштейн, _G823, _G824), (эйнштейн, 23, _G842), _G835] ; E = [(эйнштейн, _G823, _G824), _G832, (эйнштейн, 87, _G842)] ; E = [(эйнштейн, _G823, _G824), _G832, (эйнштейн, 23, _G842)] ; - person bex91; 17.05.2013
comment
Извините, я не знаю, как правильно отформатировать текст здесь :( Проблема в том, что он распространяет Эйнштейна на остальную часть списка. Есть ли способ избежать этого? - person bex91; 17.05.2013
comment
поместите отсечение после вашего решения, которое зафиксирует сделанный выбор. Или используйте раз/1, может быть понятнее. Но в целом вам не нужно заботиться об этом, чтобы получить выгоду от декларативности Пролога. Если применимо, конечно, это зависит от контекста. - person CapelliC; 17.05.2013

Я бы написал так:

predicate(M1,M2,M3,L):- member(M1,L),member(M1,[M2,M3]).

вы говорите: «Здесь сказано, что M1 является либо M2, либо M3, но не обоими», но я думаю, что это ваша ответственность как вызывающего этого предиката. Если вы предоставили равные M2 и M3, очевидно, вы хотели чтобы они были равными. И если вы снабдили их другими, ну, это то, что они есть.

person Will Ness    schedule 17.05.2013
comment
Привет, спасибо за отзыв. Хотя я не совсем понимаю, что вы имеете в виду. Предположим, я получаю этот ввод: predicate((einstein,-,-),(-,32,-),(-,-,пловец),L). В нем говорится, что Эйнштейну либо 32 года, либо он пловец, но не то и другое одновременно. Имея M1=M2, M1=M3 было бы верно, что не работает в соответствии с моим предикатом. - person bex91; 17.05.2013
comment
@bex вы не объясняете / не показываете пример вызова использования. Может быть, я неправильно вас понял. - person Will Ness; 17.05.2013

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

predicate(M1,M1,M3,[_]) :- M1 \= M3.
predicate(M1,M2,M1,[_]) :- M1 \= M2.

На самом деле это говорит о том же, но эта версия обращает внимание на тот факт, что мы ничего не делаем с четвертым аргументом, который в этой формулировке может быть любым одноэлементным списком. Скорее всего, это не то, что вы имели в виду.

person Daniel Lyons    schedule 17.05.2013