我一直在尝试在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.
我似乎无法弄清楚我做错了什么。
答案 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).
如果Head
,Head >= 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 .
如果我们在上面的查询中使用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
不是单调的!