2009-11-22 2 views
1

У меня есть база данных, состоящая из следующих правил;Список прологов вопрос

speaks(fred [german, english, dutch]). 
speaks(mary [spanish, arabic, dutch]). 
speaks(jim [norwegian, italian, english]). 
speaks(sam [polish, swedish, danish]). 

и т.д.

В рамках гораздо более крупной программы, как бы я узнать, 3 людей, которые говорят на одном языке?

Джен

+5

Если не то 'говорит (Фреда, [немецкий , английский, голландский]). '(обратите внимание на дополнительную запятую)? Также: это домашнее задание? Если это так, пожалуйста, пометьте его как домашнюю работу. – Franz

+0

У этого есть немного домашнего труда. – nedned

ответ

0

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

% Find out whether an element is contained in a list 
in_list(X,[X|_]). 
in_list(X,[First|Rest]) :- in_list(X,Rest). 

% Find out 3 people who speak the same language 
findspeakers(Language, X1, X2, X3) :- speaks(X1, L1), speaks(X2, L2), speaks(X3, L3), in_list(Language, L1), in_list(Language, L2), in_list(Language, L3). 

Довольно простое решение, используя список операторов (я не сделал помните, было ли встроенное правило для выяснения, содержится ли переменная в списке, поэтому я переписал ее).

Вы можете узнать группы из трех людей, говорящих на английском язык с помощью следующей команды:

findspeakers('English', X1, X2, X3). 

Вы можете найти все группы из трех людей говорит на одном языке с помощью следующей команды:

findspeakers(Language, X1, X2, X3). 

ПРИМЕЧАНИЕ: Эти команды предоставят вам все возможные комбинации групп из трех человек, поэтому, если у вас есть четыре человека, говорящих по-английски, первая команда даст вам четыре набора результатов.

+0

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

+0

Также существует предикат, который делает то, что делает ваш 'in_list/2':' member/2'. Я не думаю, что это в стандарте ISO, но он должен иметь почти универсальную поддержку в качестве расширения. – bcat

+0

Ах, круто. Спасибо за комментарии. Особенно интересен первый из них - я не знал, что ... – Franz

3

Как бы то ни было, Franz' solution не будет работать: он возвращает тройки проформы, которые говорят на одном языке, но эти тройки могут содержать дубликаты. Таким образом, все равно придется прибегать к, например, sort/2 и length/2, чтобы найти ответ на исходный вопрос:

?- findspeakers(Language, X1, X2, X3), sort([X1, X2, X3], Y), length(Y, 3). 
false. 

(Так что ответ нет, нет три людей, говорящих на одном языке.) Во всяком случае, я думаю, более элегантное решение существует:

spoken(L, S) :- 
    speaks(S, LL), member(L, LL). 

same_language(N, L, SS) :- 
    bagof(S, spoken(L, S), SS), length(SS, N). 

предикат spoken/2 использует member/2 и успешна, если язык L говорят лица S. same_language/3 подходит, если в списке SS содержится N разные люди, все из которых говорят на языке L. В этом предикате используется bagof/3; если определение предиката speak/2 содержит повторяющиеся данные, то вместо этого вы должны использовать setof/3.

Заметим, что это хорошо обобщается проблему: теперь мы можем ответить на вопрос, для любогоп, а не только 3. Демонстрация:

?- same_language(3, L, SS). 
false. 

?- same_language(2, L, SS). 
L = dutch, 
SS = [fred, mary] ; 
L = english, 
SS = [fred, jim] ; 
false. 
+0

Ничего себе. отличный ответ. Твое превосходит мои знания Пролога много;) – Franz

+0

Да, мое тоже. Я хотел узнать, как работают 'bagof' и' setof', и это хороший пример для рисования. – bcat

Смежные вопросы