【问题标题】:Get the output value from a Prolog recursive function从 Prolog 递归函数获取输出值
【发布时间】:2019-02-23 00:48:57
【问题描述】:

我这几天正在学习 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]]

如果有人能指出原因,我们将不胜感激。谢谢。

【问题讨论】:

    标签: prolog


    【解决方案1】:

    我在这六行代码中看到了相当多的混乱。以下是一些有问题的线索:

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

    我认为这里发生的事情是您认为将内容添加到列表中的唯一且正确的方法是使用 append/3,这不是真的。我认为 Prolog 的单赋值语义进一步说服了您,您需要另一个参数来创建空列表供您附加。你错过了递归的基本情况,所以你永远不会得到合理的回报;让它敞开至少让你变得真实,但没有给你束缚。这里的根本问题是您的代码中没有合理的关系。让我们再试一次。

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

    % extend_path(Path, Possibilities, NewPaths)
    

    这里不需要第四个参数,因为你不需要知道到目前为止你在创建 NewPaths 时做了什么,你可以为当前的可能性构建路径,并且知道递归正在处理休息。

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

    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匹配,然后将剩余的输入与剩余的输出匹配。

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

    希望这会有所帮助!

    【讨论】:

    • 非常感谢您的回答。您的解释有助于我更好地理解 Prolog。
    • @RogerRoger 好,我希望你了解 Prolog! :)
    【解决方案2】:

    与其尝试修复现有代码,不如尝试重新解决问题。您展示示例:

    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([a,b,c], [1,2], [], Result).
    Result = [[1,2,a],[1,2,b],[1,2,c]]
    

    第三个参数看起来完全格格不入,与第一批示例相比,第一个和第二个参数互换了,所以假设它应该是

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

    所以我们 开始编码,只需列出我们知道必须持有的案例:

    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]]).
    

    概括它给我们

    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!
    

    如果只有两个呢?

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

    所以我们实际上可以将它在语法上重写为

    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]  ).
    

    但是看!无论我们对这三个元素做什么,我们都在做同样的事情,本质上,对这两个元素。

    为什么我们要把自己限制在三个或两个元素的情况下?这些没什么特别的。让我们再次概括一下,

    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 ).
    

    你能从这里拿走吗?

    【讨论】:

    • 感谢您的回答。
    • 不客气。如果有帮助的话,我会重视您的反馈意见?你能跟上吗?它有趣吗?它给了你一个aha的时刻吗? :) 我猜它没有...但是也许您稍后会回到它,当您对 Prolog 更满意时...
    猜你喜欢
    • 2021-08-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-20
    • 1970-01-01
    • 2014-08-21
    相关资源
    最近更新 更多