Prolog 递归调用规则时如何停止回溯

Prolog 递归调用规则时如何停止回溯,prolog,Prolog,所以我有一个问题应该很容易解决,到了这里,我知道我正在做的这个程序的流程 之前有代码,但我在这里粘贴的这段代码调用如下: pairs_nodes_arcs(C, C, SalidaCreacionEnum, EnumArcos). 它应该做什么:遍历第二个参数,直到它为空,找出它是否满足所有条件,如果满足,则给出形成的输出列表(EnumArcos应保留答案),因为条件是“答案”(我打算发送“向上”通过回溯到代码的其余部分,因为这是真正问题的答案之一) 现在,如果失败了,它应该(并且确实)删除第

所以我有一个问题应该很容易解决,到了这里,我知道我正在做的这个程序的流程

之前有代码,但我在这里粘贴的这段代码调用如下:

pairs_nodes_arcs(C, C, SalidaCreacionEnum, EnumArcos).
它应该做什么:遍历第二个参数,直到它为空,找出它是否满足所有条件,如果满足,则给出形成的输出列表(EnumArcos应保留答案),因为条件是“答案”(我打算发送“向上”通过回溯到代码的其余部分,因为这是真正问题的答案之一)

现在,如果失败了,它应该(并且确实)删除第三个参数的头部,这是一个列表,并“重新启动”第二个参数(我也成功地这样做了,因为我始终持有第一个参数的副本,它与第二个参数的原始副本相同)

正如我所说,它应该返回,在第四个参数中,答案列表。确实如此,当我使用trace时,我在那里看到了正确的答案(最后!!),但它会丢失,因为当它回溯时,答案列表会是空的,而我最终会返回空的

我刚刚在这里读到,基本查询是必需的。但我无法理解(严格来说,我的代码不会进入无限循环,即使是因为运气不好,也不是问题所在)。问题是当回溯时,我失去了答案

pairs_nodes_arcs(_, _, [],_).
pairs_nodes_arcs(_, [], _,_).
pairs_nodes_arcs([], _, _, _).
pairs_nodes_arcs([A-B | T],[C-D | Tail0], [H|NODES], LISTARCS) :-
    member(enum(NODE_ID_C, C), H),
    member(enum(NODE_ID_D, D), H),
    REMAINDER is abs(NODE_ID_C-NODE_ID_D),
    arcs_are_repeated([A-B  | T], [C-D | Tail0], [H|NODES], REMAINDER,LISTARCS).

arcs_are_repeated([A-B | T], [_ | Tail0], [H|NODES], REMAINDER, ListArcsInput):-
    %maplist(dif(enum(REMAINDER,_)), ListArcsInput),
    myMapList(enum(REMAINDER,_),ListArcsInput),
    pairs_nodes_arcs([A-B | T], Tail0, [H|NODES], [enum(REMAINDER, A-B) | ListArcsInput], ).

arcs_are_repeated([A-B | T], [_], [H|NODES],_,_):-
    pairs_nodes_arcs([A-B | T], [A-B | T], NODES, []).


myMapList(_, []).
myMapList(enum(NUM1,_), [enum(NUM2,_)|InputList]):-
    dif(NUM1,NUM2),
    myMapList(enum(NUM1,_), InputList).
我也有跟踪,我只粘贴了我感觉“失去答案”的特定部分(我手动分离第四个参数以强调它,它都是同一个括号的一部分):

edit1好的,到目前为止,我解决这个问题的方法似乎是传递一个空列表,我操作它,以及一个我一直为自己保留的变量。然后,当成功的基本情况成功时,我将解决方案的操作列表与变量统一起来。我在代码中至少这样做了3次,并且还需要它1次。这不是100%的成功虽然这样做很好,但我最终还是有很多论点,但……我的意思是,这种方法似乎有问题,但至少有一个问题。

你的答案不是关于回溯(回溯发生在失败时),但关于成功:您希望您的程序通过特定的绑定成功,但实际并非如此

要调试这一点,以陈述的方式思考:写下一个目标,应该成功,但失败

在您的示例中,查询:

?- arcs_are_repeated([a-b, b-c], [b-c], [[enum(1, c), enum(3, b), enum(2,a)], [enum(2, c), enum(1, b), enum(3, a)], [enum(2, c), enum(3, b), enum(1, a)], [enum(3, c), enum(1, b), enum(2, a)], [enum(3, c), enum(2, b), enum(1, a)]], 2, [enum(1, a-b)]). ?弧_重复([a-b,b-c],[b-c],[enum(1,c),enum(3,b),enum(2,a)], [枚举(2,c),枚举(1,b),枚举(3,a)],[枚举(2,c),枚举(3,b),枚举(1,a)], [枚举(3,c),枚举(1,b),枚举(2,a)],[枚举(3,c),枚举(2,b),枚举(1,a)], 2、[enum(1,a-b)])。 可能就是这样一个例子

然后,使目标更一般化,使其仍然失败。例如,以下目标是否仍然失败:

?- arcs_are_repeated([a-b, b-c], [b-c], [[enum(1, c), enum(3, b), enum(2,a)], [enum(2, c), enum(1, b), enum(3, a)], [enum(2, c), enum(3, b), enum(1, a)], _], 2, _). ?弧_重复([a-b,b-c],[b-c],[enum(1,c),enum(3,b),enum(2,a)], [enum(2,c),enum(1,b),enum(3,a)],[enum(2,c),enum(3,b),enum(1,a)],[u3],2,[u3]。 如果是,请进一步概括。例如,关于:

?- arcs_are_repeated([a-b, b-c], _, _, _, _). -弧是重复的([a-b,b-c],[u,[u,]。 如果这样做失败,那么您就缩小了尚未考虑的案例范围,不管这些论点是什么

以下是声明式调试的方式:考虑什么应该成功,但失败,以及什么应该失败,但成功。在前一种情况下,您的程序是toospecific,而在后一种情况下,它是toogeneral。在您的情况下,它太具体了,因此您需要:

  • 添加一个子句或
  • 删除现有子句中的约束

使程序更通用。

目前正在检查您的答案以了解它(顺便说一句,我们仍在处理前一个程序的部分,代码很难,但我觉得总体上有所改进).我只是想说声谢谢,有时候我不知道如何回答自己为什么我要上大学。你在我的老师那里取得了成功,仅仅是因为缺乏兴趣(正确解释概念),失败。谢谢。我正在应用的方法依赖于几年前还没有广泛和免费使用的技术。例如,CLP(FD)约束在更少(更昂贵)的版本中可用系统。
dif/2
并没有得到广泛的应用。现在可以使用的东西需要几年甚至几十年的时间才能传播到教科书和教师教育中,并从那里传播到下一代Prolog程序员。例如,如果你仍然使用低级算术谓词r非单调构造,如
!/0
。一旦程序正确,很有可能在Ciao中运行,最多只需进行一些小的更改。使用安全近似。此外,您仍然可以在提供此重要约束的Prolog系统中调试代码,并学习如何更具声明性地思考。稍后,您可以使用不纯谓词es,记住它们破坏了代码的关系属性,严重限制了特定方向和使用模式的通用性。这绝对做到了!!很高兴,我真的很感谢。我现在至少有一个案例在它的预期程序中按预期工作。这是一种解脱。我现在打算寻找案例,看看list be(上次我检查时,任何大于9个节点的操作都会导致程序内存不足),然后回去阅读你告诉我要做的一切。至少,看看#=和正确的命名规则。可能遗漏了什么,但我会重新阅读所有内容。再次感谢你的编辑1:这肯定是一种方法。更好的方法是进一步实例化一个部分列表,以便在edicate成功。例如,您从
Ls0
开始,然后 ?- arcs_are_repeated([a-b, b-c], _, _, _, _).