用Prolog找到所有亲戚

时间:2012-05-09 03:31:42

标签: prolog

我无法理解如何返回与某个人相关的所有人的清单。所以,如果我说亲戚(A,B),A就是一个人而B就是与该人有关的所有人的名单。我可以编写协助这样做所需的任何其他规则。这是我到目前为止所拥有的。

man(joe).
man(tim).
man(milan).
man(matt).
man(eugene).

woman(mary).
woman(emily).
woman(lily).
woman(rosie).
woman(chris).

parent(milan, mary).
parent(tim, milan).
parent(mary, lily).
parent(mary, joe).
parent(mary, matt).
parent(chris, rosie).
parent(eugene, mary).
parent(eugene, chris).

cousins(A, B) :- parent(C, A), parent(D, B), parent(E, C), parent(E, D), not(parent(C, B)), not(parent(D, A)), A \=B.

paternalgrandfather(A, C) :- man(A), man(B), parent(B, C), parent(A, B).

sibling(A, B) :- parent(C, A), parent(C, B), A \= B.

有人可以指导我如何做到这一点吗?感谢。

2 个答案:

答案 0 :(得分:0)

我认为你应该使用内置的谓词findall / 3和sort / 2来避免重复

它会沿着这些方向发展:

relatives(Person, Relatives):-
  findall(Relative, is_relative(Person, Relative), LRelatives),
  sort(LRelatives, Relatives).

is_relative(Person, Relative):-
  (cousins(Person, Relative) ; paternalgrandfather(Person, Relative) ; sibling(Person, Relative)).

您可能希望向is_relative添加更多子句以获得更多关系。

答案 1 :(得分:0)

我认为你应该专注于'真正的'关系,即parent(Old,Jung),其他谓词在这里是无关紧要的。显而易见的假设是parent/2中出现的原子是标识符(即名称是唯一的)。从这张图看来,这里的所有人都是亲戚:

enter image description here

那么你的问题应该等同于在父关系中找到所有连接的顶点。您可以实现深度优先访问,传递受访节点列表以避免循环(请注意,您需要返回父母和孩子们!),类似

relatives(Person, Relatives) :-
    relatives([], Person, [Person|Relatives]).

relatives(Visited, Person, [Person|Relatives]) :-
    findall(Relative, immediate(Person, Visited, R), Immediates),
    ... find relatives of immediates and append all in relatives.

immediate(Person, Visited, R) :-
    (parent(Person, R) ; parent(R, Person)),
    \+ member(R, Visited).

看看您是否可以完成此代码段。请注意,relatives / 3中的参数顺序选择为easy maplist / 3。

如果您愿意学习更高级的代码,SWI-Prolog library(ugraph)会提供reachable(+Vertex, +Graph, -Vertices)谓词,在基于列表的图表表示中执行此操作。

此处用于获取图片的SWI-Prolog代码段(要提供给dot的文件):

graph(Fact2) :-
    format('digraph ~s {~n', [Fact2]),
    forall(call(Fact2, From, To), format(' ~s -> ~s;~n', [From, To])),
    format('}\n').
你可以这样打电话:

?- tell('/tmp/parent.gv'),graph(parent),told.

然后在命令行dot -Tjpg /tmp/parent.gv | display

上发布