给定带有成员谓词的查询时回溯如何工作的困惑

时间:2018-07-28 12:43:24

标签: prolog

假设我调用查询member(a, [c,b,a,y]),输出为-

true ;
false.

我们为什么会有“另一种解决方案”?为什么我们不能在true.结束?

这是痕迹:

%% [trace]  ?- member(a,[c,b,a,y]).
%%    Call: (6) member(a, [c, b, a, y]) ?
%%    Call: (7) member(a, [b, a, y]) ?
%%    Call: (8) member(a, [a, y]) ?
%%    Exit: (8) member(a, [a, y]) ?
%%    Exit: (7) member(a, [b, a, y]) ?
%%    Exit: (6) member(a, [c, b, a, y]) ?
%% true ;
%%    Redo: (8) member(a, [a, y]) ?
%%    Call: (9) member(a, [y]) ?
%%    Call: (10) member(a, []) ?
%%    Fail: (10) member(a, []) ?
%%    Fail: (9) member(a, [y]) ?
%%    Fail: (8) member(a, [a, y]) ?
%%    Fail: (7) member(a, [b, a, y]) ?
%%    Fail: (6) member(a, [c, b, a, y]) ?
%% false.

我不明白我们如何回溯到(8),为什么?


member(X,[X|_]).
member(X,[Y|T]) :- member(X,T).

1 个答案:

答案 0 :(得分:4)

让我们将其重写为几乎等效的单线纸

membr(X,[A|B]):- ( X = A ; membr(X,B) ).

追踪可能会更清楚:

[trace] 5 ?- trace, membr(a, [c,b,a,y]).         X=a
   Call: (8) membr(a, [c, b, a, y]) ? creep        [A8|B8]=[c,b,a,y]
   Call:  (9) a=c ? creep                            X=A8 ?
   Fail:  (9) a=c ? creep                            false
   Redo: (8) membr(a, [c, b, a, y]) ? creep        membr(X,B8) ?
   Call:  (9) membr(a, [b, a, y]) ? creep            [A9|B9]=B8
   Call:   (10) a=b ? creep                            X=A9 ?
   Fail:   (10) a=b ? creep                            false
   Redo:  (9) membr(a, [b, a, y]) ? creep            membr(X,B9) ?
   Call:   (10) membr(a, [a, y]) ? creep               [A10|B10]=B9
   Call:    (11) a=a ? creep                             X=A10 ?
   Exit:    (11) a=a ? creep                             true
   Exit:   (10) membr(a, [a, y]) ? creep               success!
   Exit:  (9) membr(a, [b, a, y]) ? creep            success!
   Exit: (8) membr(a, [c, b, a, y]) ? creep        success!
true ;
   Redo:   (10) membr(a, [a, y]) ? creep               membr(X,B10) ?
   Call:    (11) membr(a, [y]) ? creep                   [A11|B11]=B10
   Call:     (12) a=y ? creep                              X=A11 ?
   Fail:     (12) a=y ? creep                              .........
   Redo:    (11) membr(a, [y]) ? creep                     .........
   Call:     (12) membr(a, []) ? creep
   Fail:     (12) membr(a, []) ? creep
   Fail:    (11) membr(a, [y]) ? creep
   Fail:   (10) membr(a, [a, y]) ? creep
   Fail:  (9) membr(a, [b, a, y]) ? creep
   Fail: (8) membr(a, [c, b, a, y]) ? creep
false.

在达到第一个成功之后,显然有一个选择点正在等待:

(10) membr(X,[A|B]):- ( X = A ; membr(X,B) ).

报告成功后,所有帧仍保留在堆栈中,从成功停止的那一刻起重试最上面的第10帧:

(10) membr(X,[A|B]):- ( X = A ; membr(X,B) ).

出口链是临时的:我们只追溯了堆栈以报告发现的值,因为它的点和点存储在导致第11帧成功的帧中({ 1}})。这些框架并没有消除,因为如果有的话,我们将只能报告第一个发现的值。但是Prolog希望报告其中的所有