Prolog - 更简洁的规则定义方式

Prolog - Cleaner way to define a rule

刚开始用 Prolog 编程,但我觉得我误解了一些概念,或者你可能需要更多规则。

我想要它所以它检查儿子是男性并且至少有一个 parent (father/mother)

% Son
son(X, Y):- male(X), father(Y, X).
son(X, Y):- male(X), mother(Y, X).

有没有什么方法可以轻松地将其组合起来,这样我就不需要两行相似的行了?可能是这样的:检查 X 是否是男性,然后检查他是否有父亲,如果没有则检查他是否有母亲。只有 return 如果 X 是男性并且有父亲 and/or 母亲。

如果你想要一个显式的析取,你可以这样写:

son(X, Y) :- male(X), (father(Y, X); mother(Y, X)).

这里我使用了;/2运算符。 A ; B 首先尝试目标 A,如果不成功,则尝试 B.

通过下面的数据,可以看出唯一的优势就是male(X)查询了两次:

male(a).
father(b, a).
mother(c, a).

原始代码的踪迹:

      1    1  Call: son(a,c) ? 
      2    2  Call: male(a) ? 
      2    2  Exit: male(a) ? 
      3    2  Call: father(c,a) ? 
      3    2  Fail: father(c,a) ? 
      2    2  Call: male(a) ?              ; <--- just this is not queried
      2    2  Exit: male(a) ? 
      3    2  Call: mother(c,a) ? 
      3    2  Exit: mother(c,a) ? 
      1    1  Exit: son(a,c) ? 

使用 ;/2 析取的新代码跟踪。

      1    1  Call: son(a,c) ? 
      2    2  Call: male(a) ? 
      2    2  Exit: male(a) ? 
      3    2  Call: father(c,a) ? 
      3    2  Fail: father(c,a) ? 
      3    2  Call: mother(c,a) ? 
      3    2  Exit: mother(c,a) ? 
      1    1  Exit: son(a,c) ? 

另一种选择是使用辅助谓词 parent/2 来包含 father/2mother/2:

parent(A, B) :- father(A, B).
parent(A, B) :- mother(A, B).

son(A, B) :- male(A), parent(B, A).

我可能会这样做,因为它能更好地表达意图:

son( X , Y ) :- male(X), parent(Y,X) .

parent( Y, X ) :- mother(Y,X) .
parent( Y, X ) :- father(Y,X) .

回答你的措辞,不是你写的代码,是

son(S):- male(S), setof( Y, (mother(Y,S) ; father(Y,S)), _).

就像你说的,儿子是一些一个的男性并且有至少一个 parent(或两个他们)。

与其他答案不同的是,同一个人如果同时有父亲和母亲,则不会被举报两次:

2 ?- [user].
son(S):- male(S), setof( Y, (mother(Y,S) ; father(Y,S)), _).
|: male(a).
|: father(b,a).
|: mother(c,a).
|: 
true.

3 ?- son(X).
X = a.