您可能会选择不使用append/3 的解决方案。例如,考虑以下谓词filter/3:
filter(_Pattern, [], []).
filter(Pattern, [E|Es], Matches) :-
Pattern \= E, !,
filter(Pattern, Es, Matches).
filter(Pattern, [E|Es], [E|Matches]) :-
filter(Pattern, Es, Matches).
filter/3 的第一个子句是基本情况,如果在第二个参数列表中没有(左)匹配,那么我们得到一个空列表。由于我们没有考虑Pattern,因此它被忽略(因此前面的_ 与变量相对)。
filter/3 的第二个子句测试Pattern,它可以绑定到一个术语(例如,foo(X,Y)),是否可以与列表的第一个元素统一匹配,E。 \= 操作符在其参数无法统一时会成功,所以如果成功了,当我们没有将E 匹配到模式时,可以将其丢弃并继续(注意剪切! 测试后提交到此分支)。
filter/3 的最后一个(第三个)子句依赖于第二个子句,因为它只是将 E 传递到最后一个参数列表 Matches 上,假设它 与 @ 匹配987654337@,因为前面的子句无法确定它不是匹配项。请注意,我们通过将列表结构绑定到输出而将E 附加到列表中,从而使Matches 子列表未绑定;完整的Matches 列表只有在到达基本情况后才会完全绑定,一旦我们用完第二个参数中的匹配项,就会将其绑定到空列表[],创建类似[E1,E2,...,En|[]] 的东西,其中每个@ 987654343@ 到 En 匹配模式;这个词等同于列表[E1,E2,...,En]。
如下测试这个谓词给出:
?- filter(foo(X,Y), [a,b,foo(x,y),c(f),foo(v(3),Z),5], L).
L = [foo(x, y), foo(v(3), Z)] ;
false.
请注意,此处与foo(X,Y) 模式一致的所有内容都已根据需要过滤到L。
最后一点:在您的代码中,调用append(foo(X,Y),R,L) 将始终失败,因为append/3 仅对列表进行操作;您可能想改为调用 append([foo(X,Y)],R,L),但在这种情况下,您只需使用 L = [foo(X,Y)|R] 作为简写。
编辑:为了匹配您有可能匹配和过滤的模式列表的特定情况,这里是另一个谓词filter_list/3:
filter_list(_Patterns, [], []).
filter_list(Patterns, [E|Es], Matches) :-
filter(E, Patterns, []), !,
filter_list(Patterns, Es, Matches).
filter_list(Patterns, [E|Es], [E|Matches]) :-
filter_list(Patterns, Es, Matches).
注意filter_list/3 取决于我之前对filter/3 的定义,并且使用完全相同的策略实现:如果E 不匹配任何Patterns(即,@ 987654359@ 成功),然后我们忘记E 并继续,否则(最后一个子句)我们保留它。测试给了我们:
?- filter_list([foo(X,Y),bar(X),b], [a,b,foo(X,Y),c], L).
L = [b, foo(X, Y)] ;
false.