我有一个看起来像
的数据库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。是否有可能只让它返回真一次?
答案 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前约定的兼容性,以获得多样化的快速容忍度:更正\+/1
到not(X)
的拼写。 :)
答案 1 :(得分:2)
这是你可以做到的另一种方式!
将您知道的所有作为Prolog事实定义,无论是正面还是负面。
在您的示例中,我们定义“正面”,例如person/1
和“否定”,例如childless/1
。当然,我们还定义了谓词child_of/2
,male/1
,female/1
,spouse_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