如何描述要满足的条件,如果不是,则继续浏览列表

时间:2016-05-30 08:29:47

标签: prolog

所以我想知道在我试图解决的问题的这个特定部分的说法是什么:

% create_arcs(CONNECTIONS_IN, NODES_IN, ARCS_OUT).  
% Create arcs - makes a list of arcs(NODE_ID_1, NODE_ID_2)...
create_arcs([], _, _).
create_arcs([A-B | T], [H|NODES], LISTARCS) :-
    ensure_arcs(A,B,H, LISTARCS, LISTARCS2),
    create_arcs(T, NODES, LISTARCS2).

%ensure_arcs(NODE_A, NODE_B, NODELIST, LISTARCSIN, LISTARCSOUT)
%builds a list of arcs TODO works WRONG when arc already was in the input. It should fail, but it just checks that is a member and moves on. So basically it works when arcs are new, because they are added properly, but not when arcs were already found (and as per the exercise it should fail and try another permutation).
ensure_arcs(A,B,NODES, LISTARCSIN, LISTARCSIN):-
    member(enum(NODE_ID_A, A), NODES),
    member(enum(NODE_ID_B, B), NODES),
    REMAINDER is abs(NODE_ID_A-NODE_ID_B),
    member(enum(REMAINDER,_), LISTARCSIN), !.

ensure_arcs(A,B,NODES, LISTARCSIN,[enum(REMAINDER, A-B) | LISTARCSIN]):-
    member(enum(NODE_ID_A, A), NODES),
    member(enum(NODE_ID_B, B), NODES),
    REMAINDER is abs(NODE_ID_A-NODE_ID_B).

如果我能够做到这一点,这里的想法是定义必须满足的条件,如果它们不是,则继续行进输入列表。

因此,试图正确地解释自己,这个想法是,如果它不符合所有条件,它应该失败并继续在列表中旅行。如果失败,则应该成功返回。我离我有多远?这仍然是观察事物的必要方式吗?

我需要知道如果不符合条件我将如何前往列表,如果不满足,请尝试其他选项;否则,如果他们满足,请停止旅行。

第二次修改:

所以我稍微更改了代码,但是我没有看到maplist(dif(enum(REMAINDER,_)), ListArcsInput),曾经说过"没有"所以它非常令人困惑。如果放在dif / 2中的内容已经在ListArcsInput中,那么它应该失败,对吧?

参考代码:

pairs_nodes_arcs(_, [],_).
pairs_nodes_arcs([], _, _).
pairs_nodes_arcs([A-B | T], [H|NODES], LISTARCS) :-
    member(enum(NODE_ID_A, A), H),
    member(enum(NODE_ID_B, B), H),
    REMAINDER is abs(NODE_ID_A-NODE_ID_B),
    arcs_are_repeated([A-B | T], [H|NODES], REMAINDER,LISTARCS).
    %maplist(dif(enum(REMAINDER,_)), LISTARCSIN),


    %pairs_nodes_arcs(T, [H|NODES], LISTARCS2),
    %pairs_nodes_arcs([A-B | T], NODES, []).

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

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

跟踪:

Call:'__aux_maplist/2_dif+1'([enum(1, a-b)], enum(1, _G3643))
 Call:dif:dif(enum(1, _G3643), enum(1, a-b))
 Exit:dif:dif(enum(1, _G3677), enum(1, a-b))
 Call:'__aux_maplist/2_dif+1'([], enum(1, _G3677))
 Exit:'__aux_maplist/2_dif+1'([], enum(1, _G3677))
 Exit:'__aux_maplist/2_dif+1'([enum(1, a-b)], enum(1, _G3677))
 Call:create_arcs([], [[enum(1, a), enum(2, b), enum(3, c)], [enum(1, a), enum(3, c), enum(2, b)], [enum(2, b), enum(1, a), enum(3, c)], [enum(2, b), enum(3, c), enum(1, a)], [enum(3, c), enum(1, a), enum(2, b)], [enum(3, c), enum(2, b), enum(1, a)]], [enum(1, b-c), enum(1, a-b)])
 Exit:create_arcs([], [[enum(1, a), enum(2, b), enum(3, c)], [enum(1, a), enum(3, c), enum(2, b)], [enum(2, b), enum(1, a), enum(3, c)], [enum(2, b), enum(3, c), enum(1, a)], [enum(3, c), enum(1, a), enum(2, b)], [enum(3, c), enum(2, b), enum(1, a)]], [enum(1, b-c), enum(1, a-b)])

我无法让地图列表工作,但我可能会变得很困难,所以我在旅途中#34;手动"列表,这意味着我自己做,并与每个元素进行比较。似乎到目前为止工作?

编辑:这是我现在使用我的所有代码获得的跟踪,其中,我想要的是,如果发生以下情况,则不应采取/接受/与当前"分支"保持一致因为它确实找到了一些东西"两次"在输出列表中,它应该跳过,回溯并尝试另一种可能性。

Call:create_arcs([b-c], [[enum(1, a), enum(2, b), enum(3, c)], [enum(1, a), enum(3, c), enum(2, b)], [enum(2, b), enum(1, a), enum(3, c)], [enum(2, b), enum(3, c), enum(1, a)], [enum(3, c), enum(1, a), enum(2, b)], [enum(3, c), enum(2, b), enum(1, a)]], [enum(1, a-b)])
 Call:ensure_arcs(b, c, [enum(1, a), enum(2, b), enum(3, c)], [enum(1, a-b)], _G3600)
 Call:lists:member(enum(_G3555, b), [enum(1, a), enum(2, b), enum(3, c)])
 Exit:lists:member(enum(2, b), [enum(1, a), enum(2, b), enum(3, c)])
 Call:lists:member(enum(_G3558, c), [enum(1, a), enum(2, b), enum(3, c)])
 Exit:lists:member(enum(3, c), [enum(1, a), enum(2, b), enum(3, c)])
 Call:_G3607 is abs(2-3)
 Exit:1 is abs(2-3)


 Call:lists:member(enum(1, _G3567), [enum(1, a-b)])
 Exit:lists:member(enum(1, a-b), [enum(1, a-b)])

这两条线,当列表中没有任何内容,或者它有,但它不匹配时,正常工作:它转到我对ensure_arcs的另一个定义,并将其添加到输出列表中。现在我想,如果有匹配的成员,失败,或回溯,或其他什么。强行做错似乎是错误的(我确定必须有某种停止或失败或其他什么,但我想知道如何编程,以便,如果它匹配,让它知道它不是一个接受的答案)。

1 个答案:

答案 0 :(得分:3)

您似乎已经非常接近解决方案了。

我有以下建议让您的谓词更强声明,也就是说,正如您所说,描述持有什么

我的第一个建议是关于谓词的名称。要获得良好的声明性名称,请选择名词形容词,并选择避免使用命令。这是因为好的关系谓词可以在所有方向中使用,而命令式总是建议使用特定的方向或模式。

例如,代替create_arcs/3,更具描述性和声明性的名称为: pairs_nodes_arcs/3 。这正确地表明您也可以使用此谓词,例如,如果已经指定了弧。

我的第二个建议是通过在整个程序中使用一般关系来实际执行隐含的一般性。在您的特定情况下,请检查您的Prolog系统的 CLP(FD)约束,并用CLP(FD)约束替换整数上的低级算术谓词(#=)/ 2 和其他人。这些关系是可逆的,除了在可以通过低级算术处理的情况下保留程序的性能之外,还会产生更多通用程序。

第三,通过避免!/ 0 和相关的非单调谓词保持所取得的一般性。在你的情况下,你已经非常接近这个理想的状态。只需删除!/0的单个匹配项即可获取所有解决方案。 (使用!/0不可避免地会削减回溯时可能需要的候选人。)

通过遵守这些原则,您将获得一个非常通用的程序,让您:

  • 测试给定解决方案
  • 完整部分实例化解决方案
  • 生成所有解决方案。

所有这一切都源于一个解决方案的 what 的单一声明性规范。

请注意,Prolog将自动完成所有可能性,直到找到满足所有约束的解决方案。专注于必须满足的属性的清晰描述。没有必要描述不是解决方案。

编辑:当然有一种方法可以使计算的当前分支失败。只需发布一个明显 false 的目标即可。恰当命名的内置谓词false/0可以做到这一点,任何其他目前无法实现的目标也是如此,例如0=1

但是,在您的情况下,更清晰的方法是明确说明解决方案的必须持有。在您的情况下,似乎有必要讨论不同的术语或整数。要表示任意字词不同,请使用dif/2谓词,请参阅。在推理整数时,您还可以使用约束(#\=)/2all_distinct/1来说明这一点。

例如,要说明只有enum(R,_)Ls中出现时关系才成立,请使用:

maplist(dif(enum(R,_)), Ls)

这只是真的如果,对于L中的每个Lsdif(enum(R,_), L) 为真

使用此以声明方式表示术语不会出现在列表中。注意:这将保留您程序的关系性。例如,如果术语是(仅或甚至,取决于您如何看待它)部分实例化,它也会起作用。

我留下了更具体的使用CLP(FD)约束的情况(而不是dif/2,它没有考虑关于整数的特定领域知识)作为一个简单的练习。