Prolog采用谓词的逆

Dan*_*tom 5 prolog

我有一个看起来像的数据库

hasChild(person1, person2).
hasChild(person1, person3).
hasChild(person4, person5).
Run Code Online (Sandbox Code Playgroud)

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

然后我创建一个谓词来识别该人是否是父母

parent(A):- hasChild(A,_).
Run Code Online (Sandbox Code Playgroud)

这表明该人是否是父母,即有任何子女

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

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

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

b)parent(A)如果该人有多个孩子,将多次返回true.是否有可能只返回一次真实?

Dan*_*ons 6

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

childless(X) :- \+ hasChild(X, _).
Run Code Online (Sandbox Code Playgroud)

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

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

parent(A) :- once(hasChild(A, _)).
Run Code Online (Sandbox Code Playgroud)

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

parent(A) :- hasChild(A, _), !.
Run Code Online (Sandbox Code Playgroud)

这具有相当大的成本:parent/1虽然它将验证其他正确的解决方案,但只生成一个有效的解决方案.以机智:

?- parent(X).
X = person1.
Run Code Online (Sandbox Code Playgroud)

注意它没有暗示person4.然而,

?- childless(person4).
true.
Run Code Online (Sandbox Code Playgroud)

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

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

parent(Person) :- 
  setof(X, C^hasChild(X, C), People), 
  member(Person, People).
Run Code Online (Sandbox Code Playgroud)

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

?- parent(person4).
true.

?- parent(X).
X = person1 ;
X = person4.
Run Code Online (Sandbox Code Playgroud)

这有效吗?不,这很聪明吗?可能不是.它是否也能解决您的问题?是的,似乎是.好吧,三分之一也不错.:)

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

  • 好,让我的一天! (2认同)