从Prolog递归函数获取输出值

时间:2018-09-18 23:14:46

标签: prolog

这些天我正在学习Prolog,需要将两个列表合并为一个遵循此规则的列表:

ListA: [], ListB: [] => ResultList: []
ListA: [], ListB:[a,b,c] => ResultList: [[a],[b],[c]]
ListA: [1,2], ListB:[a,b,c] => ResultList: [[1,2,a],[1,2,b],[1,2,c]]

我遇到了递归函数输出值问题,这是我的代码:

extend_my_path([],_,_,_).
extend_my_path([H|T],OriginalPath,OrignailMewPaths,NewPaths) :-
    append(OriginalPath,[H],NewPath),
    append(OrignailMewPaths,[NewPath],NewPaths1),
    print("NewPaths1:"),print(NewPaths1), nl,
    extend_my_path(T,OriginalPath,NewPaths1,NewPaths1).

运行它会得到以下结果,而没有Result变量的值:

?- extend_my_path([a,b,c],[1,2],[],Result).
"NewPaths1:"[[1,2,a]]
"NewPaths1:"[[1,2,a],[1,2,b]]
"NewPaths1:"[[1,2,a],[1,2,b],[1,2,c]]
true.

我希望获得其价值,例如:

Result=[[1,2,a],[1,2,b],[1,2,c]]

非常感谢任何人指出原因。谢谢。

2 个答案:

答案 0 :(得分:4)

在这六行代码中,我看到了很多困惑。以下是一些不对劲的线索:

  • 您的问题是用三件事来定义的,但是您的谓词有四个参数。最后两个应该是什么?
  • 您有一个单例变量NewPaths,这很灾难
  • 您的基本案例将一个空列表与任何其他三件事相关联!试试看:extend_my_path([], lightning, [the,sound,of,rain], "fresh coffee")是真的!这似乎不太符合您的预期。
  • 有人想知道“原始喵喵路径”是什么,或者“路径”与这里的任何内容有什么关系。错别字,请解决!
  • 归纳案例以NewPaths1的两个副本结尾,这似乎很可疑,因为开始时我们有两个非常不同的变量,正如您在基本案例中看到的那样,它们无关紧要。奇怪!

我认为这里发生的事情是您认为唯一正确的向列表添加内容的方法是使用append/3,这是不正确的。我认为Prolog的单分配语义进一步使您相信,您需要另一个参数来创建要附加到的空列表。您错过了递归的基本情况,因此您从未获得明智的回报。让它敞开,至少可以使您成为现实,但并没有给您带来约束力。这里的根本问题是代码中没有合理的 relation 。让我们再试一次。

您正在尝试编写一个谓词,其名称和参数更像这样:

% extend_path(Path, Possibilities, NewPaths)

这里不需要第四个参数,因为您不需要知道到目前为止在创建NewPath中所做的事情,您可以为当前可能性构建路径,并且知道递归正在处理休息。

您的基本情况将是您没有更多可能性,因此没有新路径的情况:

extend_path(_, [], []).

这没有说任何相关的东西,而是说:“当我没有可能的时候,任何前缀的路径扩展都是空的。”

然后,您的归纳案例采用您的第一个参数,并将其附加到可能性列表中的下一项。这会在您的新路径列表中。

extend_path(Prefix, [Ext1|ExtRest], [Next1|NextRest]) :-
    append(Prefix, [Ext1], Next1),
    extend_path(Prefix, ExtRest, NextRest).

这从字面上说:“给定一些前缀,并且我的扩展名列表中剩下一个Ext,将产生新的路径扩展名Next1,例如:Prefix + [Ext1]为Next1。”实际上,它与递归步骤相比要说的更多。但是这里的想法是咬掉一块Ext1,然后将其与结果Next1的一部分匹配,然后将其余的输入与其余的输出匹配。 / p>

最后,不要将单例变量“警告”视为警告。这不是,就像Python发疯的那样,您在函数之间没有足够的换行符。单例变量几乎总是 严重错误,特别是对于Prolog的新用户!注意他们!

希望这会有所帮助!

答案 1 :(得分:1)

Instead of trying to fix your existing code let's try solving the problem afresh. You show the examples:

ListA: [],    ListB: []      => ResultList: []
ListA: [],    ListB: [a,b,c] => ResultList: [[a],[b],[c]]
ListA: [1,2], ListB: [a,b,c] => ResultList: [[1,2,a],[1,2,b],[1,2,c]]

and

?- extend_my_path([a,b,c], [1,2], [], Result).
Result = [[1,2,a],[1,2,b],[1,2,c]]

The third argument looks completely out of place, and the first and the second arguments are swapped compared to the first batch of examples, so let's say it's supposed to be

?- ListA = [1,2], ListB = [a,b,c], extend_my_path( ListA, ListB, ResultList).
ResultList = [[1,2,a],[1,2,b],[1,2,c]]

So we start coding by just listing the cases we know must hold:

extend_my_path_ex( [], [], []).
extend_my_path_ex( [],    [a,b,c], [[    a],[    b],[    c]]).
extend_my_path_ex( [1,2], [a,b,c], [[1,2,a],[1,2,b],[1,2,c]]).

Generalizing it gives us

extend_my_path3( [], [], []). 
extend_my_path3( OneTwo, [A,B,C], [OneTwoA,OneTwoB,OneTwoC]):-
    append( OneTwo, [A], OneTwoA),
    append( OneTwo, [B], OneTwoB),    % ... right? all the examples produce 
    append( OneTwo, [C], OneTwoC).    %     the same answers. check it!

And what if there were only two of them?

extend_my_path2( [], [], []).  
extend_my_path2( OneTwo,   [B,C],         [OneTwoB,OneTwoC]):-
    append( OneTwo, [B], OneTwoB),
    append( OneTwo, [C], OneTwoC).    % ... right? 

So we can actually just re-write it syntactically as

extend_my_path3( [], [], []). 
extend_my_path3( OneTwo, [A | [B,C]], [OneTwoA | [OneTwoB,OneTwoC] ]):-
    append(      OneTwo, [A],          OneTwoA),
    extend_my_path2( OneTwo,  [B,C],             [OneTwoB,OneTwoC]  ).

But look! Whatever we were doing with the three elements, we are doing the same thing, essentially, with the two.

And why should we limit ourselves to the three, or the two elements cases only? There's nothing special about those. Let's generalize once more,

extend_my_path( [], [], []).
extend_my_path( OneTwo, [A | B_C], [OneTwoA | OneTwoB_OneTwoC ]):-
    append(     OneTwo, [A],        OneTwoA),
    extend_my_path( OneTwo,  B_C,             OneTwoB_OneTwoC ).

Can you take it from here?