4

我为最近的问题Segregating Lists in Prolog提供了以下基于 clpfd 的代码:

list_evens_odds([],[],[]).
list_evens_odds([X|Xs],[X|Es],Os) :-
   X mod 2 #= 0,
   list_evens_odds(Xs,Es,Os).
list_evens_odds([X|Xs],Es,[X|Os]) :-
   X mod 2 #= 1,
   list_evens_odds(Xs,Es,Os).

它简洁而纯粹,会留下许多不必要的选择点。考虑:

?- list_evens_odds([1,2,3,4,5,6,7],Es,Os).

上面的查询为 中的每个非奇数项留下了一个无用的选择点[1,2,3,4,5,6,7]

替代实施

使用@false 在 AUBUC 的Prolog union 中演示的具体化技术可以减少不必要的选择点的数量。实施可能会更改为:

list_evens_odds([],[],[]).
list_evens_odds([X|Xs],Es,Os) :-
   if_(#<=>(X mod 2 #= 0), (Es=[X|Es0],Os=   Os0),
                           (Es=   Es0, Os=[X|Os0])),
   list_evens_odds(Xs,Es0,Os0).

直接与 clpfd-reification 交互,if_/3可以像这样调整实现:

if_( C_1, Then_0, Else_0) :-
   call(C_1,Truth01),
   indomain(Truth01),
   ( Truth01 == 1 -> Then_0 ; Truth01 == 0, Else_0 ).

当然,(=)/3也需要适应这种约定。

底线

所以我想知道:使用0and1作为真值而不是falseandtrue是个好主意吗?

我在那条路上错过了问题吗?请帮忙!先感谢您!

4

3 回答 3

1

在 SWI-Prolog 中,您可以使用zcompare/3

:- use_module(library(clpfd)).

list_evens_odds([], [], []).
list_evens_odds([X|Xs], Es, Os) :-
      Mod #= X mod 2,
      zcompare(Ord, 0, Mod),
      ord_(Ord, X, Es0, Es, Os0, Os),
      list_evens_odds(Xs, Es0, Os0).

ord_(=, X, Es0, [X|Es0], Os, Os).
ord_(<, X, Es, Es, Os0, [X|Os0]).

示例查询:

?- list_evens_odds([1,2,3,4,5,6,7], Es, Os).
Es = [2, 4, 6],
Os = [1, 3, 5, 7].
于 2015-04-08T11:55:53.417 回答
1

我重新考虑了我提议的“双重用途”,if_/3我觉得我现在看的更好了。

@false 和 @lurker 的评论以及 @mat 的回答在帮助我理解方面发挥了应有的作用。谢谢!

我获得的“洞察力”绝不是戏剧性的。我仍然想与您分享它们:

  1. if_/3像我一样适应是可行的,并且可能与一些 LOC 相同。
  2. 但是,它混合了两个在程序上完全不同的概念:默认情况下,clpfd 传播然后延迟。物化术语平等OTOH立即迫使选择。
  3. 因此,将这两个用例分开会更清晰。当然,“清洁确实仅次于虔诚”……
于 2015-04-08T13:10:34.970 回答
0

直接的解决方案(适用于任何可具体化的 clp(fd) 条件)似乎是

:- use_module(library(clpfd)).

list_evens_odds([],[],[]).
list_evens_odds([X|Xs],Es,Os) :-
   B #<==> (X mod 2 #= 0),
   freeze(B, (B=1 -> Es=[X|Es0],Os=Os0 ; Es=Es0,Os=[X|Os0])),
   list_evens_odds(Xs,Es0,Os0).

0/1 或真/假是否被用作真值在这里并不重要。在算术求解器中首选 0/1 约定的原因很简单,因为您可以轻松地在算术约束中重用真值,例如将它们相加等。

于 2015-04-08T10:06:22.417 回答