我有一个带有2个列表的递归子句,在每次递归调用中我都会从列表中删除一个元素并将这个新列表(删除了元素)绑定到一个新变量。
如果我写这个变量,这是正确完成的。但是当我有一个模型时,它会回溯到最后一个绑定(我需要的列表)到之前绑定所取消的那个变量。
我试图在这段代码中复制这种情况:
test([],Test,Result).
test([H|T],Test,Result):-
member(H,Test),
delete(Test,H,Test1),
write(Test1),
write('\n'),
test(T,Test1,Test1).
test([H|T],Test,Test1):-
test(T,Test,Test1).
?- test([1,2,3],[5,2,4,6,1],R).
我确实理解结果应该在这个条款的头部:
test([H|T],Test,Test1)....
但是只有第一次递归调用会成功,这是我不想要的。
如何解决这个问题的任何线索?
另外,我对prolog很新,只是阅读一些关于互联网的教程并做了简单的练习
答案 0 :(得分:0)
filter([], []).
filter([Head|Tail], [Head|Result]) :-
sometest(Head),
filter(Tail, Result).
filter([Head|Tail], Result) :-
\+ sometest(Head),
filter(Tail, Result).
现在,要了解其工作原理,请在运行trace/0
谓词之前尝试发出filter/2
调用,这将详细说明执行情况(至少在swi pl中):
考虑这个谓词sometest/1
:
sometest(N) :- N mod 2 =:= 0.
现在让我们触发跟踪模式:
?- trace.
true.
现在,让我们打电话给你的谓词:
[trace] ?- filter([1, 2, 3], R).
Call: (6) filter([1, 2, 3], _G522) ? creep
Call: (7) sometest(1) ? creep
Call: (8) 1 mod 2=:=0 ? creep
Fail: (8) 1 mod 2=:=0 ? creep
Fail: (7) sometest(1) ? creep
Redo: (6) filter([1, 2, 3], _G522) ? creep
Call: (7) sometest(1) ? creep
Call: (8) 1 mod 2=:=0 ? creep
Fail: (8) 1 mod 2=:=0 ? creep
Fail: (7) sometest(1) ? creep
Call: (7) filter([2, 3], _G522) ? creep
Call: (8) sometest(2) ? creep
Call: (9) 2 mod 2=:=0 ? creep
Exit: (9) 2 mod 2=:=0 ? creep
Exit: (8) sometest(2) ? creep
Call: (8) filter([3], _G597) ? creep
Call: (9) sometest(3) ? creep
Call: (10) 3 mod 2=:=0 ? creep
Fail: (10) 3 mod 2=:=0 ? creep
Fail: (9) sometest(3) ? creep
Redo: (8) filter([3], _G597) ? creep
Call: (9) sometest(3) ? creep
Call: (10) 3 mod 2=:=0 ? creep
Fail: (10) 3 mod 2=:=0 ? creep
Fail: (9) sometest(3) ? creep
Call: (9) filter([], _G597) ? creep
Exit: (9) filter([], []) ? creep
Exit: (8) filter([3], []) ? creep
Exit: (7) filter([2, 3], [2]) ? creep
Exit: (6) filter([1, 2, 3], [2]) ? creep
R = [2] ;
false.
如果您花时间了解prolog在这里做了什么,那基本上就是:只要您没有找到谓词为真,您就会运行(基本情况,此处为filter([], [])
),然后您可以向后构建列表,具体取决于您为达到此案例所采用的路径。这意味着,如果某个测试属于真,则在Head
中添加Result
,如果不是,则不添加。{/ p>
请注意,您需要像我一样在第二个子句中使用\+ condition
(这意味着无法证明条件),或者在第一个中使用cut,如下所示,否则匹配Head
在回溯过程中仍然会经历第二个条款:
filter([], []).
filter([Head|Tail], [Head|Result]) :-
sometest(Head),
!,
filter(Tail, Result).
filter([Head|Tail], Result) :-
filter(Tail, Result).
现在,如果你使用swi-pl,请注意你可以直接使用include/3
来实现你想要的东西(它在其他实现中也存在于这个名称或其他实现中):
?- include(sometest, [1, 2, 3, 4, 5], R).
R = [2, 4].
希望它有所帮助。