为什么使用[H | T]作为参数而不是普通变量导致我的谓词失败?

时间:2015-02-23 21:40:47

标签: list prolog

我正在创建一个谓词来从列表中删除指定的元素,因此如果Ys是删除所有出现的结果,则删除(Xs,X,Ys)应该成立 来自X的X。我最初的失败谓词如下所示:

remove([],_,[]).
remove([H1|T1],H1,[H2|T2]) :- % e.g. [2,3] , 2, [3]
   remove(T1,H1,[H2|T2]).     % remove first head -> [3], 2, [3]
remove([H1|T1],Y,[H1|T2]) :-  % heads match e.g. [1,2,3], 2, [1,3]
   H1\==Y,
   remove(T1,Y,T2).           % remove heads -> [2,3], 2, [3]

这是失败但后来我注意到我有一个多余的[H2|Y2]我可以使用一个变量,例如Ys。我做了这个改变,认为它仍然会失败,但它开始工作。工作代码如下所示:

remove([],_,[]).
remove([H1|T1],H1,Ys) :-      % e.g. [2,3] , 2, [3]
   remove(T1,H1,Ys).          % remove first head -> [3], 2, [3]
remove([H1|T1],Y,[H1|T2]) :-  % heads match e.g. [1,2,3], 2, [1,3]
   H1\==Y,
   remove(T1,Y,T2).           % remove heads -> [2,3], 2, [3]

有人可以解释为什么将[H2|T2]更改为Ys会使其有效吗?

1 个答案:

答案 0 :(得分:1)

在查询进展的某个地方,模式remove([H|T], H, [])即将出现,它将匹配第二个版本remove([H1|T1], H1, Ys)的第二个子句的头部,但不匹配第一个版本的第二个子句remove([H1|T1], H1, [H2|T2])

如果您使用第一个程序版本对查询remove([1, 2, 3, 2], 2, [1, 3])运行跟踪,则会得到:

   Call: (6) remove([1, 2, 3, 2], 2, [1, 3]) ? creep
   Call: (7) 1\==2 ? creep
   Exit: (7) 1\==2 ? creep
   Call: (7) remove([2, 3, 2], 2, [3]) ? creep
   Call: (8) remove([3, 2], 2, [3]) ? creep
   Call: (9) 3\==2 ? creep
   Exit: (9) 3\==2 ? creep
   Call: (9) remove([2], 2, []) ? creep
   Fail: (9) remove([2], 2, []) ? creep   <---- NOTE THIS FAILURE! (no clause match)
   Fail: (8) remove([3, 2], 2, [3]) ? creep
   Redo: (7) remove([2, 3, 2], 2, [3]) ? creep
   Fail: (7) remove([2, 3, 2], 2, [3]) ? creep
   Fail: (6) remove([1, 2, 3, 2], 2, [1, 3]) ? creep

案例remove([2], 2, [])与第一个实现的第二个子句不匹配:

remove([H1|T1], H1, [H2|T2])...

所以H1 = 2T1 = [],但[H2|T2][]无法统一。

但它将匹配第二个实现的第二个条款:

remove([H1|T1], H1, Ys).

您可以获得H1 = 2T1 = []Ys = []。这是第二个版本的跟踪:

[trace]  ?- remove([1,2,3,2],2,[1,3]).
   Call: (6) remove([1, 2, 3, 2], 2, [1, 3]) ? creep
   Call: (7) 1\==2 ? creep
   Exit: (7) 1\==2 ? creep
   Call: (7) remove([2, 3, 2], 2, [3]) ? creep
   Call: (8) remove([3, 2], 2, [3]) ? creep
   Call: (9) 3\==2 ? creep
   Exit: (9) 3\==2 ? creep
   Call: (9) remove([2], 2, []) ? creep   <---- SUCCESS! (2nd clause match)
   Call: (10) remove([], 2, []) ? creep   <---- SUCCESS!
   Exit: (10) remove([], 2, []) ? creep
   Exit: (9) remove([2], 2, []) ? creep
   Exit: (8) remove([3, 2], 2, [3]) ? creep
   Exit: (7) remove([2, 3, 2], 2, [3]) ? creep
   Exit: (6) remove([1, 2, 3, 2], 2, [1, 3]) ? creep