Prolog中的前向链接,多个规则的问题

Forward chaining in Prolog, problem with multiple rules

在我之前的 最佳答案中,我找到了 Prolog 中前向链接的一个很好的例子。我对它做了一些修改,但我尝试定义的最后一条规则 (path) 有问题。它不起作用。以目前的事实,我应该可以推导出path([a,b,c,d,e]),但是不行。

转发码:

:- op(1100, xfx, if).
:- op(1000, xfy, and).
:- op(900, xfy, or).
:- dynamic rule/1.                                                       

forward(Facts) :-
    fixed_point(nil, [true], Facts).                % Start with the base with only true

fixed_point(Base, Base, Base) :- !.                 % Reached a fixpoint
fixed_point(_, Base, Facts) :-                      % Base =/= Facts => not a fixpoint
    setof(Fact, derived(Fact, Base), NewFacts),     % Derive new facts
    ord_union(NewFacts, Base, NewBase),             % Add new facts to base
    fixed_point(Base, NewBase, Facts).              % Repeat with new base

derived(Fact, Base) :-                              
    rule(Fact if Condition),                        % Match a rule
    satisfy(Base, Condition).                       % Verify if condition is satisfied given base

satisfy(Base, Condition) :-
    Condition =.. [and, Elem|Bag],!,
    member(Elem, Base),                                     
    (   Bag = []
    ->  true
    ;   NewAtom =.. [and|Bag],       
        satisfy(Base, NewAtom)).
satisfy(Base, Condition) :-
    Condition =.. [or, Elem|Bag],!,
    (   member(Elem, Base)
    ->  true
    ;   (   Bag = []
        ->  false
        ;   NewAtom =.. [or|Bag],       
            satisfy(Base, NewAtom))).
satisfy(Base, Condition) :-
    member(Condition, Base),!.
satisfy(_, true):-!.
satisfy(_, false):-!,fail.

规则和事实如下:

rule(eats_flies(fritz) if true).
rule(croaks(fritz)     if true).
rule(eats_flies(frotz) if true). % ADDED IN EDIT
rule(croaks(frotz)     if true). % ADDED IN EDIT
rule(sings(tweety)     if true).
rule(chips(tweety)     if true).
rule(has_wings(tweety) if true).
rule(croaks(krogr)    if true).
rule(chips(kroger)     if true).
rule(canary(X)         if and(sings(X),chips(X),has_wings(X))).
rule(frog(X)           if and(croaks(X),eats_flies(X))).
rule(green(X)          if frog(X)).
rule(yellow(X)         if canary(X)).
rule(node(a) if true).
rule(node(b) if true).
rule(node(c) if true).
rule(node(d) if true).
rule(node(e) if true).
rule(connected(a,b) if true).
rule(connected(b,c) if true).
rule(connected(c,d) if true).
rule(connected(d,e) if true).
rule(funny(c,d) if true).
rule(wonderful(X,Y) if or(nice(X,Y),funny(X,Y))).
rule(connected(X,Z) if and(connected(X,Y),connected(Y,Z))).
rule(path([Node|[]]) if node(Node)).
rule(path([Node, NextNode|Nodes]) if and(connected(Node, NextNode),path([NextNode|Nodes]))).

关键规则:

rule(path([Node|[]]) if node(Node)).
rule(path([Node, NextNode|Nodes]) if and(connected(Node, NextNode),path([NextNode|Nodes]))).

我得到的前向输出:

?- forward(A).
A = [true,canary(tweety),chips(kroger),chips(tweety),croaks(fritz),croaks(krogr),eats_flies(fritz),frog(fritz),green(fritz),has_wings(tweety),node(a),node(b),node(c),node(d),node(e),path([a]),sings(tweety),yellow(tweety),connected(a,b),connected(a,c),connected(b,c),connected(c,d),connected(d,e),funny(c,d),wonderful(c,d)].

编辑:

测试代码我发现另一个问题是如果我添加类似的规则,例如:

rule(eats_flies(fritz) if true).
rule(croaks(fritz)     if true).
rule(eats_flies(frotz) if true).
rule(croaks(frotz)     if true).

转发只会发现fritz是一个frog,而不是frotz

您的代码中存在一些问题:

  • 运算符univ=..)使用不当,直接使用合一(=)。看看为什么:
    ?- (p and q and r) =.. [and,G|Gs], N =.. [and|Gs].
    G = p,                        % <== this is the first goal of the condition
    Gs = [(q and r)],
    N = and((q and r)).           % <== this IS NOT a valid conjunction of the remaining goals
    
    ?- (p and q and r) = (G and Gs).
    G = p,                        % <== this is the first goal of the condition
    Gs =  (q and r).              % <== this IS a valid conjunction of the remaining goals 
    
  • 不要在 satisfy(Base, Condition) :- member(Condition, Base), !. 中使用 cut,因为这会阻止谓词 member/2 回溯以找到备选答案(例如,frog(fritz)frog(frotz))。
  • 因为最初 Base 是集合 [true],所以不需要子句 satisfy(_, true) :- !.。请注意 true 已经自然地满足子句 satisfy(Base, Condition) :- member(Condition, Base).
  • 在 Prolog 中,你只需要声明什么是真的,所以不需要子句 satisfy(_, false):- !, fail..

考虑到所有这些观察结果,正确的代码如下:

:- op(1100, xfx, if).
:- op(1000, xfy, and).
:- op(900, xfy, or).
:- dynamic rule/1.

forward(Facts) :-
    fixed_point(nil, [true], Facts).                % Start with the base with only true

fixed_point(Base, Base, Base) :- !.                 % Reached a fixpoint
fixed_point(_, Base, Facts) :-                      % Base =/= Facts => not a fixpoint
    setof(Fact, derived(Fact, Base), NewFacts),     % Derive new facts
    ord_union(NewFacts, Base, NewBase),             % Add new facts to base
    fixed_point(Base, NewBase, Facts).              % Repeat with new base

derived(Fact, Base) :-
    rule(Fact if Condition),                        % Match a rule
    satisfy(Base, Condition).                       % Verify if condition is satisfied given base

satisfy(Base, G and Gs) :-    % Condition unifies with (G and Gs)
    !,
    member(G, Base),
    satisfy(Base, Gs).

satisfy(Base, G or Gs) :-     % Condition unifies with (G or Gs)
    !,
    (   member(G, Base)
    ;   satisfy(Base, Gs) ).

satisfy(Base, Condition) :-   % Condition is an atomic proposition
    member(Condition, Base).

% Knowledge base

rule(eats_flies(fritz) if true).
rule(croaks(fritz)     if true).
rule(eats_flies(frotz) if true). 
rule(croaks(frotz)     if true). 
rule(sings(tweety)     if true).
rule(chips(tweety)     if true).
rule(has_wings(tweety) if true).
rule(croaks(krogr)    if true).
rule(chips(kroger)     if true).
rule(canary(X)         if and(sings(X),chips(X),has_wings(X))).
rule(frog(X)           if and(croaks(X),eats_flies(X))).
rule(green(X)          if frog(X)).
rule(yellow(X)         if canary(X)).
rule(node(a) if true).
rule(node(b) if true).
rule(node(c) if true).
rule(node(d) if true).
rule(node(e) if true).
rule(connected(a,b) if true).
rule(connected(b,c) if true).
rule(connected(c,d) if true).
rule(connected(d,e) if true).
rule(funny(c,d) if true).
rule(wonderful(X,Y) if or(nice(X,Y),funny(X,Y))).
rule(connected(X,Z) if and(connected(X,Y),connected(Y,Z))).
rule(path([Node|[]]) if node(Node)).
rule(path([Node, NextNode|Nodes]) if and(connected(Node, NextNode),path([NextNode|Nodes]))).

示例:

?- forward(Base), member(path(P), Base), length(P, 5).
Base = [true, chips(kroger), chips(tweety), croaks(fritz), croaks(frotz), croaks(krogr), eats_flies(fritz), eats_flies(frotz), frog(...)|...],
P = [a, b, c, d, e] .

?- forward(Base), member(frog(X), Base).
Base = [true, chips(kroger), chips(tweety), croaks(fritz), croaks(frotz), croaks(krogr), eats_flies(fritz), eats_flies(frotz), frog(...)|...],
X = fritz ;
Base = [true, chips(kroger), chips(tweety), croaks(fritz), croaks(frotz), croaks(krogr), eats_flies(fritz), eats_flies(frotz), frog(...)|...],
X = frotz ;
false.

REMARK 我没有检查你所有代码的正确性,只检查最相关的部分以获得你想要的答案。但是我看到您分配给运算符 or 的优先级是不够的,因为逻辑连接词 or 的优先级低于逻辑连接词 (请注意,在谓词op/3中,较小的数字表示较高的优先级)。