Prolog谓词(\=)/2已忽略

Prolog谓词(\=)/2已忽略,prolog,Prolog,开始使用prolog,我正在尝试做一些简单的练习,但是我很早就被卡住了。。。我想说的是:迈克喜欢任何男人或女人,而不是迈克。但是,X\=mike似乎被忽略了: man(mike). man(danny). man(samuel). man(henry). woman(samantha). woman(jane). woman(betty). woman(jenny). likes(mike, X) :- man(X); woman(X), X \= mike. 迈克

开始使用prolog,我正在尝试做一些简单的练习,但是我很早就被卡住了。。。我想说的是:迈克喜欢任何男人或女人,而不是迈克。但是,
X\=mike
似乎被忽略了:

man(mike).
man(danny).
man(samuel).
man(henry).

woman(samantha).
woman(jane).
woman(betty).
woman(jenny).

likes(mike, X) :-
    man(X);
    woman(X),
    X \= mike.
迈克出现了

?- findall(X, likes(mike, X), L).
L = [mike, danny, samuel, henry, samantha, jane, betty, jenny].
我认为这是因为prolog首先计算规则
man(X)
,所以mike是
true
。但是,如果我将其更改为:

likes(mike, X) :-
    X \= mike,
    man(X);
    woman(X).
我只会得到女人

?- findall(X, likes(mike, X), L).
L = [samantha, jane, betty, jenny].
问题是如何做到这一点?谢谢

注意:我正在使用swi prolog

问题在于运算符():

您的解决方案:

likes(mike, X) :- (man(X);woman(X)),X\=mike.
另一种解决方案(使用与OR运算符等效的运算符)可以是:

likes(mike, X) :- man(X), X\=mike.
likes(mike, X) :- woman(X).

请注意,您不需要OR运算符。

问题在于运算符优先级。只有C/C#/Java/SQL和其他过程语言,在Prolog中,逻辑OR(
)的优先级与逻辑and(“,”)的优先级不同

在大多数过程语言中,表达式

A || B && C
被解析为

A | |(B&C)

在Prolog中,类似于您的表达式

A ; B , C    
像写的一样被解析

A ; (B,C)
那么你的

likes(mike, X) :-
  man(X);
  woman(X),
  X \= mike.
本质上是

likes(mike,X) :- man(X) ; ( woman(X) , X \= mike ) .
你是说迈克喜欢任何一个

  • 男人(包括他自己),或
  • 不是迈克的女人
你的意思是迈克喜欢任何人,不管是男是女,除了他自己

所以…你需要用括号来明确优先级

likes(A,B) :- ( man(B) ; woman(B) ) , A \= B .
或者更好的方法是,将谓词分成两个子句,并使其成为泛型:

likes(A,B) :- man(B)   , A \= B .
likes(A,B) :- woman(B) , A \= B .
通过将性别作为实体(一个人)的属性而不是事实本身来进一步改善事物:

person( mike     , male ) .
person( danny    , male ) .
person( samuel   , male ) .
person( henry    , male ) .
person( samantha , female ) .
person( jane     , female ) .
person( betty    , female ) .
person( jenny    , female ) .
那么
likes/2
就更简单了,因为人们可以喜欢两性的人:

likes(A,B) :- person(B,_) , A \= B .

除了OR问题之外,还有另一个问题。谓词(\=)/2不是约束,意味着它本质上不是完全声明性谓词

谓词通常是通过作为失败的否定来引导的,而作为失败的否定本身并不是完全声明的

谓词从普通统一中引导,如下所示:

X \= Y :- \+ X = Y.
另一种定义是:

X \= X :- !, fail.
_ \= _.
如果你真的想绕过这个不等式,你应该使用带有约束的Prolog系统,然后求助于dif/2

使用dif/2,您可以编写:

likes(mike, X) :-
    (dif(X, mike),
     man(X)
  ;  woman(X)).
或以下各项:

likes(mike, X) :-
    (man(X),
     dif(X, mike)
  ;  woman(X)).
你会得到同样的结果。这在
(\=)/2
中是不可能的

再见

备注:
(\=)/2
出现问题的原因。作为失败的否定有时不仅充当失败的否定,而且还充当失败的否定。感兴趣的读者可能想涉猎一些公认的古老但仍然适用的内容:

逻辑程序的否定证明理论 罗伯特·斯特尔克,伯尔尼,1992年

由于运算符优先级,
man(X);女人(X),X\=mike。
被解释为男人(X);(女人(X),X\=mike)。。您可以用括号来更改,将
分组
(男人(X);女人(X)),X\=迈克。
。这也是第二个例子的问题之一。查看有关的信息。比如说
列出(喜欢)
!它会立即向您显示问题。标题有点奇怪。实际上(\=)/2不是规则,而是谓词。这个谓词用于规则中的文本。
likes(mike, X) :-
    (man(X),
     dif(X, mike)
  ;  woman(X)).