prolog中的递归,绑定到变量

时间:2012-01-06 16:40:50

标签: binding recursion 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很新,只是阅读一些关于互联网的教程并做了简单的练习

1 个答案:

答案 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].

希望它有所帮助。