我试图解决一个问题,为您提供一系列事实,例如:
parent(a,b).
其中b
是a
的父级,
我需要写一个子句来确定某人是否至少有3个父母。
这是我的尝试
has3Parent(A) :- parent(A,B), parent(A,C), parent(A,D).
通过我的尝试
如果A
有1个父级,它将一次返回true,
如果A
有2个父母,它将返回true 8次,
如果A
有3个父母,它将返回正确的27次。
对于Prolog来说我还很陌生,所以我无法确定为什么会这样,所以任何帮助将不胜感激。
答案 0 :(得分:2)
因为您从未保证B
,C
和D
是不同的人,所以只要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个父母,您必须说除了B
,C
和D
有所不同外,也没有E
与所有父母不同这也是一种parent
。findall
解决方案很容易适应各种比较,因为您要处理的是数字,而不是一堆不规则的变量。)
答案 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), [_,_,_|_]).