我有一个递归子句,它接受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还很陌生,只是在互联网上读了一些教程,并做了一些简单的练习
filter([], []).
filter([Head|Tail], [Head|Result]) :-
sometest(Head),
filter(Tail, Result).
filter([Head|Tail], Result) :-
+ sometest(Head),
filter(Tail, Result).
现在,要了解它的工作原理,请尝试在运行filter/2
谓词之前发出trace/0
调用,该调用将详细说明执行情况(至少在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([], [])
),你就会运行,然后根据你到达这种情况的路径向后构建你的列表。这里的意思是,如果sometest为true,则在Result
中添加Head
,否则不添加。
请注意,您需要像我一样在第二个子句中使用+ 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].
希望它能有所帮助。