如何增加分离度?

时间:2014-01-09 22:25:37

标签: prolog

在Prolog中,我如何制定一个规则来检查一个人网络中有多少人进入,然后查询其分离程度?

例如,如果在Facebook,我的名字是约翰;我有一个朋友汤姆,汤姆有一个朋友露西,露西有一个朋友本,本有一个朋友约什,约什有一个朋友南希。

我想在Prolog中创建一个规则来测试我的网络中有多少人,并告诉Prolog将名称返回到给定的分离度。

e.g。如果我查询类似的东西;

?- mynetwork(josh,2).

Prolog应该返回

  • 约翰
  • 汤姆

  • 约翰是汤姆的朋友
  • 汤姆是露西的朋友

1 个答案:

答案 0 :(得分:4)

欢迎来到Prolog!

首先,你需要一些事实:

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(读取 - 评估 - 打印循环)来完成I / O.这是与Prolog合作的自然方式。如果您遇到一些麻烦,将I / O和用户表示的谓词与关注意义的谓词分开,那么您以后会为自己省去很多心痛。这只是模型视图分离的小型应用。您还可以将副作用隔离在自己的谓词中。只要程序的纯逻辑部分是自包含的,您就可以随时构建和编写它。

  

您如何打印给定数量的人。例如如果你输入网络(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]).