Prolog采用谓词的逆

时间:2015-11-24 23:30:31

标签: prolog

我有一个看起来像

的数据库
hasChild(person1, person2).
hasChild(person1, person3).
hasChild(person4, person5).

这意味着(例如)person1的孩子名为person2。

然后我创建一个谓词,用于识别此人是否为父

parent(A):- hasChild(A,_).

确定此人是否为父母,即有任何子女

然后我尝试创建一个谓词childless(A),如果用户没有任何基本上与parent(A)相反的子项,则应返回true。

所以我在这里有两个问题:

a)是否有可能以某种方式采用谓词的“逆”,如childless(A):-not(parent(A)).或以任何其他方式使用hasChild或任何其他方法绕过这个?

b)如果此人有多个孩子,parent(A)将多次返回true。是否有可能只让它返回真一次?

2 个答案:

答案 0 :(得分:6)

对于问题1,是的。 Prolog对某些人来说并不完全神奇,因为它混淆了否定和失败,但你绝对可以写:

childless(X) :- \+ hasChild(X, _).

你会看到" true"对于没有孩子的人。你也会看到" true"用于蔬菜,矿物,意识形态,程序,鞋盒,啤酒食谱和未风化的两足动物。如果这对您来说是一个问题,一个简单的解决方案是改善您的数据模型,但抱怨Prolog是一个非常受欢迎的选择。 :)

对于问题2,最简单的解决方案是使用once

parent(A) :- once(hasChild(A, _)).

这是使用cut运算符的更安全的替代方法,如下所示:

parent(A) :- hasChild(A, _), !.

这具有相当大的成本:parent/1只会生成一个有效的解决方案,但它会验证其他正确的解决方案。即:

?- parent(X).
X = person1.

请注意,它没有建议person4。但是,

?- childless(person4).
true.

这种不对称肯定是一种代码味道"对于像我这样的大多数中级Prolog程序员。就好像Prolog根据查询有某种健忘症或选择性听力一样。这无法被邀请参加上流社会活动!

我建议这里最好的解决方案(处理上面的矿物/蔬菜问题)是增加一些关于人的事实。毕竟,一个人在他们有孩子之前就存在(或者他们是吗?)因此他们没有定义"通过那种关系。但是继续玩游戏,您可以使用setof/3来构建所有人的列表来解决问题:

parent(Person) :- 
  setof(X, C^hasChild(X, C), People), 
  member(Person, People).

奇怪的表达式C^hasChild(X, C)告诉Prolog C是一个自由变量;这可以确保我们获得绑定到列表hasChild/2的{​​{1}}的第一个参数中的所有内容集。这不再是一阶逻辑了!这里的优点是People将为我们生成以及检查:

member/2

效率这么高吗?不,这很聪明吗?可能不是。它是否也能解决您的问题?是的,似乎是。好吧,三分之一的人不好。 :)

作为最后的评论,一些Prolog实现将?- parent(person4). true. ?- parent(X). X = person1 ; X = person4. 视为not/1的别名;如果您碰巧使用其中之一,我建议您不要误解与ISO前约定的兼容性,以获得多样化的快速容忍度:更正\+/1not(X)的拼写。 :)

答案 1 :(得分:2)

这是你可以做到的另一种方式!

  

将您知道的所有作为Prolog事实定义,无论是正面还是负面。

在您的示例中,我们定义“正面”,例如person/1 “否定”,例如childless/1。当然,我们还定义了谓词child_of/2male/1female/1spouse_husband/2等等。

请注意,我们已在数据库中引入了相当多的冗余。

作为回报,我们得到了更清晰的knowns/unknowns行,而没有求助于更高阶的构造。

我们需要定义正确的数据一致性约束:

% There is no person which is neither male nor female.
:- \+ (person(X), \+ (male(X) ; female(X))).

% Nobody is male and female (at once).
:- \+ (male(X), female(X)).

% Nobody is childless and parental (at once).
:- \+ (childless(X), child_of(_,X)).

% There is no person which is neither childless nor parental.
:- \+ (person(X), \+ (childless(X) ; child_of(_,X))).

% There is no child which is not a person.
:- \+ (child_of(X,_), \+ person(X)).

% There is no parent which is not a person.
:- \+ (child_of(_,X), \+ person(X)).

% (...plus, quite likely, a lot more integrity constraints...)

这只是一个粗略的草图......根据您的使用情况,您可以进行不同的建模,例如:使用parental/1之类的关系以及合适的完整性约束。 YMMY! HTH