将整数列表拆分为正整数列表和负整数列表

时间:2012-03-03 14:56:59

标签: list split prolog clpfd

我一直在尝试在Prolog中创建一个谓词,它将整数列表拆分为正整数列表和负整数列表。

具有预期结果的示例查询:

?- split([1,-2,3,4,-8],X,Y).
X = [1,3,4],
Y = [-2,-8].

这是我到目前为止的代码:

split([], [], []).
split([Head|Tail], List1, List2) :- split(Tail, [Head|List1], List2), Head>=0.
split([Head|Tail], List1, List2) :- split(Tail, List1, [Head|List2]), Head<0.

我似乎无法弄清楚我做错了什么。

4 个答案:

答案 0 :(得分:9)

递归部分不太正确。

split([], [], []).
split([Head|Tail], [Head|List1], List2) :- Head>=0, split(Tail, List1, List2).
split([Head|Tail], List1, [Head|List2]) :- Head<0, split(Tail, List1, List2).

如果HeadHead >= 0应添加到肯定列表,Head < 0时应添加到否定列表。

此外,在开头检查Head 的符号更好,因为它可以防止不必要的递归调用。

答案 1 :(得分:6)

在SWI-Prolog中,您可以使用谓词partition/4(通常从apply模块自动加载):

?- partition(=<(0), [1,-2,3,4,-8,0], X, Y).
X = [1, 3, 4, 0],
Y = [-2, -8].

答案 2 :(得分:3)

这是使用约束的定义。在这种情况下,它是SWI和YAP的library(clpfd)(也可能是XSB)。这个库很通用,它包含了常规整数用法。

:- use_module(library(clpfd)).

使用具体化:

split([], [], []).
split([E|Es], Poss, Negs) :-
   E #>= 0 #<==> B,
   i_split(B, E, Es, Poss, Negs).

i_split(1, E, Es, [E|Poss], Negs) :-
   split(Es, Poss, Negs).
i_split(0, E, Es, Poss, [E|Negs]) :-
   split(Es, Poss, Negs).

或者,您可以使用zcompare/3,我更喜欢该版本:

split([], [], []).
split([E|Es], Poss, Negs) :-
   zcompare(Order, E, 0),
   c_split(Order, E, Es, Poss, Negs).

c_split(>, E, Es, [E|Poss], Negs) :-
   split(Es, Poss, Negs).
c_split(=, E, Es, [E|Poss], Negs) :-
   split(Es, Poss, Negs).
c_split(<, E, Es, Poss, [E|Negs]) :-
   split(Es, Poss, Negs).

您可以将它用于常规查询,以及更常见的查询,例如

?- split(Es,[A],[]).
Es = [A],
A in 1..sup ;
Es = [0],
A = 0 ;
false.

答案 3 :(得分:2)

保持逻辑纯粹且高效。怎么样?使用元谓词tpartition/4(#=<)/3

首先,让我们定义(#=<)/3,即基于(#=<)/2的具体版本 在bool01_t/2上。
为了完整起见,我们还要定义(#<)/3(#>)/3(#>=)/3

#=<(X,Y,Truth) :- X #=< Y #<==> B, bool01_t(B,Truth).

#<( X,Y,Truth) :- X #<  Y #<==> B, bool01_t(B,Truth).

#>( X,Y,Truth) :- X #>  Y #<==> B, bool01_t(B,Truth).

#>=(X,Y,Truth) :- X #>= Y #<==> B, bool01_t(B,Truth).

那就是它!现在,让我们做OP想要的拆分:

?- tpartition(#=<(0),[1,-2,3,4,-8,0],Ts,Fs).
Ts = [1,3,4,0], Fs = [-2,-8].                   % succeeds deterministically

这是单调,因此即使使用一般的非基础术语,我们也会获得声音答案

?- tpartition(#=<(0),[A,B,C],Ts,Fs).
Ts = [     ], Fs = [A,B,C], A in inf.. -1, B in inf.. -1, C in inf.. -1 ;
Ts = [    C], Fs = [A,B  ], A in inf.. -1, B in inf.. -1, C in   0..sup ;
Ts = [  B  ], Fs = [A,  C], A in inf.. -1, B in   0..sup, C in inf.. -1 ;
Ts = [  B,C], Fs = [A    ], A in inf.. -1, B in   0..sup, C in   0..sup ;
Ts = [A    ], Fs = [  B,C], A in   0..sup, B in inf.. -1, C in inf.. -1 ;
Ts = [A,  C], Fs = [  B  ], A in   0..sup, B in inf.. -1, C in   0..sup ;
Ts = [A,B  ], Fs = [    C], A in   0..sup, B in   0..sup, C in inf.. -1 ;
Ts = [A,B,C], Fs = [     ], A in   0..sup, B in   0..sup, C in   0..sup .

编辑2015-06-02

如果我们在上面的查询中使用SWI-Prolog库谓词partition/4怎么办?

?- partition(#=<(0),[A,B,C],Ts,Fs).
Ts = [A,B,C], Fs = [], A in 0..sup, B in 0..sup, C in 0..sup.

我们将失去8个解决方案中的7个,因为partition/4不是单调的!