prolog中的递归,绑定到变量



我有一个递归子句,它接受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].

希望它能有所帮助。

最新更新