如何添加分离度?

0 prolog

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

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

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

例如,如果我查询类似的内容;

?- mynetwork(josh,2).
Run Code Online (Sandbox Code Playgroud)

Prolog 应该返回

  • 约翰
  • 汤姆
  • 露西

或者

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

Dan*_*ons 5

欢迎来到普罗格!

首先你需要一些事实:

friend(john, tom).
friend(tom, lucy).
friend(lucy, ben).
...
Run Code Online (Sandbox Code Playgroud)

为简单起见,让我们考虑一下友谊定向的情况:我可以加你为好友,但这并不意味着你也加我为好友。

如果我加你为好友,我们就可以说我们是 1 级好友。那看起来像这样:

network(Person, 1, Friend) :- friend(Person, Friend).
Run Code Online (Sandbox Code Playgroud)

现在归纳的情况是我们通过朋友找到了朋友。看起来像这样:

network(Person, N1, FoaF) :-
  N1 > 1, 
  N0 is N1-1,
  network(Person, N0, Friend),
  network(Friend, 1, FoaF).
Run Code Online (Sandbox Code Playgroud)

使用is/2you 可以确定谓词将表现不良。例如,如果您省略> 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).
Run Code Online (Sandbox Code Playgroud)

这应该适用于您想要尝试的所有输入情况,尽管它仍然无法知道您何时超出友谊级别。

?- 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.
Run Code Online (Sandbox Code Playgroud)

编辑让我不按顺序回答你的问题。

打印语句在哪里?

根据设计,我没有使用过。到目前为止,我们只是使用 Prolog REPL(读取-求值-打印循环)来执行 I/O。这是使用 Prolog 的自然方式。如果您费尽心思将执行 I/O 和用户表示的谓词与与含义相关的谓词分开,那么您以后会省去很多心痛。这只是模型视图分离的一个小型应用。您还可以受益于将副作用隔离在它们自己的谓词中。只要程序的纯逻辑部分是独立的,您就始终能够使用它进行构建和组合。

您将如何打印给定数量的人员。例如,如果您输入 network(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(_, _).
Run Code Online (Sandbox Code Playgroud)

这将像这样工作:

?- show_network(john, 3).
john is friends with tom.
john is friends with lucy.
john is friends with ben.
true.
Run Code Online (Sandbox Code Playgroud)

还有其他方法,例如,您可以使用forall/2

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

故障驱动循环与该循环之间的关系应该非常清楚。您还可以手动获取列表,然后使用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]).
Run Code Online (Sandbox Code Playgroud)