2014-01-09 2 views
0

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

Например, если в Facebook меня зовут Джон; и у меня есть один друг Том, и у Тома есть одна подруга Люси, а у Люси один друг Бен, а у Бена один друг Джош, а у Джоша есть одна подруга Нэнси.

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

например. если я запрошу что-то вроде;

?- mynetwork(josh,2). 

Пролог должен вернуться

  • Джон
  • Том
  • Люси

или

  • Джон дружит с Томом
  • Том дружит с Люси

ответ

4

Добро пожаловать на Прологе!

Сначала вы будете нуждаться некоторые факты:

friend(john, tom). 
friend(tom, lucy). 
friend(lucy, ben). 
... 

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

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

network(Person, 1, Friend) :- friend(Person, Friend). 

Теперь индуктивный случай - это тот, в котором мы нашли друга через друга. Это будет выглядеть так:

network(Person, N1, FoaF) :- 
    N1 > 1, 
    N0 is N1-1, 
    network(Person, N0, Friend), 
    network(Friend, 1, FoaF). 

Использование is/2 вы можете быть уверены, что предикат будет плохо себя вели. Например, если вы опустите ограничение > 1, вы сможете задать вопросы и получить N обратно, если вы его не включите. Но вы также получите ошибки в отсутствии локального стека. Так что если вы можете позволить себе, привести в clpfd Сейчас:

:- use_module(library(clpfd)). 

network(Person, 1, Friend) :- friend(Person, Friend). 
network(Person, N1, FoaF) :- 
    N1 #> 0, 
    N0 #= N1-1, 
    network(Person, N0, Friend), 
    network(Friend, 1, FoaF). 

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

?- network(john, N, X). 
N = 1, 
X = tom ; 
N = 2, 
X = lucy ; 
N = 3, 
X = ben ; 
^CAction (h for help) ? abort 
% Execution Aborted 

?- network(john, 3, X). 
X = ben ; 
false. 

?- network(john, 2, X). 
X = lucy ; 
false. 

Редактировать Позвольте мне ответить на ваши вопросы по порядку.

Где печать?

По дизайну, я не использовал его.До сих пор мы просто используем Prolog REPL (цикл чтения-eval-print) для ввода ввода-вывода. Это естественный способ работы с Prolog. Позднее вы избавитесь от боли, если у вас возникнут проблемы с разделением предикатов, которые делают ввод-вывод и презентацию пользователя из предикатов, имеющих значение. Это всего лишь небольшое применение разделения модели. Вы также можете сохранить побочные эффекты на карантине в своих собственных предикатах. Пока чистая логическая часть вашей программы является самодостаточной, вы всегда сможете создавать и компоновать ее.

Как вы можете печатать до определенного количества людей. например если вы введете сеть (john, 3, X). то он должен распечатываться до N = 3 X = ben

Я бы склонен называть этот предикат show_network/2 вместо этого и продолжать разделение. Вы можете сделать это по дешевке с отказом управляемой петли следующим образом:

show_network(Person, Max) :- 
    between(1, Max, N), 
    network(Person, N, Friend), 
    format('~w is friends with ~w\n', [Person, Friend]), 
    fail. 
show_network(_, _). 

Это будет работать следующим образом:

?- show_network(john, 3). 
john is friends with tom. 
john is friends with lucy. 
john is friends with ben. 
true. 

Там находятся и другие подходы, например, вы могли бы использовать forall/2:

show_network(Person, Max) :- 
    forall(
    (between(1, Max, N), network(Person, N, Friend)), 
    format('~w is friends with ~w\n', [Person, Friend])). 

Взаимосвязь между циклом, управляемым отказами, и который должен быть довольно ясным. Вы также можете вручную получить список, а затем обработать его maplist/2 или что-то:

show_network(Person, Max) :- 
    findall(friend(Person,Friend), 
      (between(1, Max, N), network(Person, N, Friend)), 
      Friends), 
    maplist(show_friend, Friends). 

show_friend(friend(Person, Friend)) :- 
    format('~w is friends with ~w\n', [Person, Friend]). 
+0

Спасибо, это очень подробно и очень полезно. У меня мало вопросов, как вы будете печатать до определенного количества людей. например если вы введете сеть (john, 3, X). то он должен распечатать до N = 3 X = ben, из приведенного выше примера. а также то, что означает FoaF, N0, use_module (library (clpfd)). Кстати, еще раз спасибо, что это очень подробно. – KennD

+0

Также где печатная заявка? – KennD

+0

Я добавил некоторое обсуждение ваших вопросов к ответу, пожалуйста, взгляните. –

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