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
中,较小的数字表示较高的优先级)。
在我之前的 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
中,较小的数字表示较高的优先级)。