检查孩子在Prolog中是否至少有3个父母

时间:2019-04-12 04:58:47

标签: prolog

我试图解决一个问题,为您提供一系列事实,例如:

parent(a,b).

其中ba的父级, 我需要写一个子句来确定某人是否至少有3个父母。

这是我的尝试

has3Parent(A) :- parent(A,B), parent(A,C), parent(A,D).

通过我的尝试

如果A有1个父级,它将一次返回true,

如果A有2个父母,它将返回true 8次,

如果A有3个父母,它将返回正确的27次。

对于Prolog来说我还很陌生,所以我无法确定为什么会这样,所以任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:2)

因为您从未保证BCD是不同的人,所以只要true甚至只有一个,您将总是得到A parent

因此,具有1 parent的情况很简单;对于2,您有以下8种组合:

A = jane, B = jane, C = jane
A = jane, B = jane, C = john
A = jane, B = john, C = jane
A = jane, B = john, C = john
A = john, B = jane, C = jane
A = john, B = jane, C = john
A = john, B = john, C = jane
A = john, B = john, C = john

即使您只是说它们不相等,对于少于3的错误,对于3或更多的错误也会为true;但您仍然会获得多种解决方案,因为顺序很重要。

理想情况下,您将使用findall/3来获取一组父母并对其进行计数,这将为您提供一个唯一的解决方案。像这样:

has3Parent(A) :- findall(P, parent(A, P), Ps), length(Ps, 3).

(还请注意,与之前的版本不同,此测试测试A是否具有完全 3个父母,而不是至少 3个父母。为了获得先前的要测试3个父母,您必须说除了BCD有所不同外,也没有E与所有父母不同这也是一种parentfindall解决方案很容易适应各种比较,因为您要处理的是数字,而不是一堆不规则的变量。)

答案 1 :(得分:0)

首先要稍作说明:您正在使用关系parent/2和类似parent(Child, Parent)的参数。许多人使用此名称和交换的参数,因此使用parent(Parent, Child)。因此,在名称中直接说明您想要的顺序更加安全。因此,child_parent(Child, Parent)是一个更好的名称,或者简称为child_of(Child, Parent)

每当您尝试定义谓词时,首先要考虑当定义取决于更改时该谓词的行为。对于您而言,如果将更多事实添加到child_of/2会发生什么情况?

您最初要求拥有至少 3个父母,所以我们将此关系称为has3parentsminimum/1。然后是正好有3个父母has3parents/1,然后是@Amadan的definition has3parentsA/1的定义。

让我们比较在将事实添加到child_of/2之前和之后的解决方案集。

has3parentsminimum/1:解决方案集增加或保持不变。如果再有一个孩子现在有3个或更多的父母,则增加。

has3parents/1:解决方案集可能增加或减少,或两者皆有(因此只是改变)。由于有些孩子现在可能有四个或更多父母,而另一些孩子现在有三个。

has3parentsA/1:类似于has3parents/1,但此外,如果添加了冗余事实,则解决方案集也可能会更改。

因此,has3parentsminimum/1在添加更多事实时非常稳定。这称为单调性:添加新的子句时,您所知道的一切都是真实的,然后再保持真实。尽可能长时间地停留在Prolog的单调子集中是一个很好的主意,因为在此部分中,您可以学到很多有关关系的知识。 (这可能就是您进行此练习的原因。)

has3parentsminimum/1最自然的定义是使用dif/2

has3parentsminimum(Ch) :-
   dif(P1,P2), dif(P1,P3), dif(P2, P3),  % all parents are different
   child_of(Ch, P1),
   child_of(Ch, P2),
   child_of(Ch, P3).

这可能是您所需要的。是的,您将获得3! =对于每个有三个父母的孩子,有6个冗余解决方案,对于有3个以上父母的孩子,甚至更多,但是解决方案集还不错。

但是有进一步的改进可能(以一定的价格)。假设child_of/2仅包含基本事实,则可以编写:

has3parentsminimum(Ch) :-
   setof(P, child_of(Ch, P), [_,_,_|_]).